From 9020e349bff012a641965b5f1b0a741c3690ccff Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 3 Apr 2018 11:47:21 -0700 Subject: [PATCH 01/59] Add @appelgriebsch as a backer - thank you! :) --- .github/config.yml | 1 + BACKERS.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/config.yml b/.github/config.yml index 6f6efd92a5..a92e3a55c0 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -26,3 +26,4 @@ backers: - 10263 - 3117205 - 5697723 +- 6803419 diff --git a/BACKERS.md b/BACKERS.md index e03d40a3f7..5b7aee2fbb 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -78,6 +78,7 @@ Thanks you to all our backers for making Oni possible! * @city41 * @nithesh * @erandac +* @appelgriebsch ## Backers via PayPal From e35e1db450cdf68b7c0449178a60bdbb24fdea99 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 3 Apr 2018 16:44:08 -0700 Subject: [PATCH 02/59] Update BACKERS.md --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index 5b7aee2fbb..031859fa81 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -4,6 +4,7 @@ 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 [Patreon](https://patreon.com/onivim) * 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) From c601fad812ba14b515ab3d8604358e3eee531b87 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 3 Apr 2018 17:01:29 -0700 Subject: [PATCH 03/59] README updates for 0.3.2 --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ddbc40cde..6492578496 100644 --- a/README.md +++ b/README.md @@ -65,16 +65,20 @@ Check out [Releases](https://github.com/onivim/oni/releases) for the latest bina Oni brings several IDE-like integrations to neovim: +* [Embedded Browser](https://github.com/onivim/oni/wiki/Features#embedded-browser) * [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) +* [Interactive Tutorial](https://github.com/onivim/oni/wiki/Features#interactive-tutorial) And more coming - check out our [Roadmap](https://github.com/onivim/oni/wiki/Roadmap) Oni is cross-platform and supports Windows, Mac, and Linux. +> If you're a Vim power user, and don't need all these features, check out our [minimal configuration](https://github.com/onivim/oni/wiki/How-To:-Minimalist-Oni-Configuration). + ## Installation We have installation guides for each platform: @@ -112,7 +116,10 @@ The goal of this project is to give an editor that gives the best of both worlds 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) +* Support Oni financially by making a donation via: + * [Patreon](https://patreon.com/onivim) + * [OpenCollective](https://opencollective.com/oni) + * [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 update our [documentation](https://github.com/onivim/oni/wiki). @@ -121,6 +128,8 @@ There many ways to get involved & contribute to Oni: * Review [PRs](https://github.com/onivim/oni/pulls) * Submit a bug fix or feature * Add test cases +* Create a blog post or YouTube video +* Follow us on [Twitter](https://twitter.com/oni_vim) ## Acknowledgements From 5d4aee2d4e6b6b8cf338236c7823fae7e8ea3aa8 Mon Sep 17 00:00:00 2001 From: Manuel Hornung Date: Wed, 4 Apr 2018 19:12:33 +0200 Subject: [PATCH 04/59] Refactor Error.tsx to styled-components (#1991) --- browser/src/CSS.ts | 1 - browser/src/UI/components/Error.less | 74 ---------- browser/src/UI/components/Error.tsx | 207 ++++++++++++--------------- 3 files changed, 94 insertions(+), 188 deletions(-) delete mode 100644 browser/src/UI/components/Error.less diff --git a/browser/src/CSS.ts b/browser/src/CSS.ts index cc2a5a88eb..3c486fe9c8 100644 --- a/browser/src/CSS.ts +++ b/browser/src/CSS.ts @@ -12,7 +12,6 @@ export const activate = () => { require("./Services/Menu/Menu.less") - require("./UI/components/Error.less") require("./UI/components/InstallHelp.less") require("./UI/components/QuickInfo.less") require("./UI/components/Tabs.less") diff --git a/browser/src/UI/components/Error.less b/browser/src/UI/components/Error.less deleted file mode 100644 index 749524f536..0000000000 --- a/browser/src/UI/components/Error.less +++ /dev/null @@ -1,74 +0,0 @@ -@import (reference) "./common.less"; - -@errorMarkerSize: 25px; - -@errorMessageSize: 200px; - -.error-marker { - position: absolute; - right: @bufferScrollBarSize; - opacity: 0.5; - width: 200px; - display: flex; - - &.active { - opacity: 0.8; - } - - .icon-container { - position: absolute; - right: 0px; - background-color: rgb(80, 80, 80); - - .fa { - padding: 6px; - } - } -} - -.error-squiggle { - position: absolute; -} - -.error { - .box-shadow; - - opacity: 0; - flex: 1 1 auto; - transition: opacity 0.2s; - position: absolute; - background-color: @background-color; - border-left: 7px solid; - padding: 6px; - margin-top: 31px; - opacity: 0px; - max-width: 400px; - - .text { - font-size: 10px; - color: @text-color; - text-overflow: ellipsis; - overflow: hidden; - } - &:before { - content: ""; - position: absolute; - left: -7px; - top: -7px; - border: 4px solid; - border-top-color: transparent; - border-right-color: transparent; - border-bottom-color: inherit; - border-left-color: inherit; - } -} -.error.top:before { - top: initial; - bottom: -7px; - border-top-color: inherit; - border-bottom-color: transparent; - margin-top: -31px; -} -.error.active { - opacity: 1; -} diff --git a/browser/src/UI/components/Error.tsx b/browser/src/UI/components/Error.tsx index f1f4bb52bc..464c362409 100644 --- a/browser/src/UI/components/Error.tsx +++ b/browser/src/UI/components/Error.tsx @@ -12,6 +12,7 @@ import * as Oni from "oni-api" import { getColorFromSeverity } from "./../../Services/Diagnostics" import { Icon } from "./../Icon" +import { bufferScrollBarSize, styled, withProps } from "./common" export interface IErrorsProps { errors: types.Diagnostic[] @@ -24,140 +25,120 @@ export interface IErrorsProps { const padding = 8 -export class Errors extends React.PureComponent { - public render(): JSX.Element { - const errors = this.props.errors || [] +export const Errors = (props: IErrorsProps) => { + const errors = props.errors || [] - if (!this.props.bufferToScreen) { + if (!props.bufferToScreen) { + return null + } + + const markers = errors.map(e => { + const screenSpaceStart = props.bufferToScreen( + types.Position.create(e.range.start.line, e.range.start.character), + ) + if (!screenSpaceStart) { return null } - const markers = errors.map(e => { - const screenSpaceStart = this.props.bufferToScreen( - types.Position.create(e.range.start.line, e.range.start.character), - ) - if (!screenSpaceStart) { - return null - } - - const screenLine = screenSpaceStart.screenY - - const screenY = screenLine - const pixelPosition = this.props.screenToPixel({ screenX: 0, screenY }) - const pixelY = pixelPosition.pixelY - padding / 2 - - return ( - - ) - }) - - const squiggles = errors - .filter(e => e && e.range && e.range.start && e.range.end) - .map(e => { - const lineNumber = e.range.start.line - const column = e.range.start.character - const endColumn = e.range.end.character - - const startPosition = this.props.bufferToScreen( - types.Position.create(lineNumber, column), - ) - - if (!startPosition) { - return null - } - - const endPosition = this.props.bufferToScreen( - types.Position.create(lineNumber, endColumn), - ) - - if (!endPosition) { - return null - } - - const pixelStart = this.props.screenToPixel(startPosition) - const pixelEnd = this.props.screenToPixel(endPosition) - const pixelWidth = pixelEnd.pixelX - pixelStart.pixelX - const normalizedPixelWidth = - pixelWidth === 0 ? this.props.fontWidthInPixels : pixelWidth - - return ( - - ) - }) + const screenLine = screenSpaceStart.screenY - return ( -
- {markers} - {squiggles} -
- ) - } -} + const screenY = screenLine + const pixelPosition = props.screenToPixel({ screenX: 0, screenY }) + const pixelY = pixelPosition.pixelY - padding / 2 -export interface IErrorMarkerProps { - y: number - text: string - color: string -} + return + }) + + const squiggles = errors.filter(e => e && e.range && e.range.start && e.range.end).map(e => { + const lineNumber = e.range.start.line + const column = e.range.start.character + const endColumn = e.range.end.character + + const startPosition = props.bufferToScreen(types.Position.create(lineNumber, column)) -export class ErrorMarker extends React.PureComponent { - public render(): JSX.Element { - const iconPositionStyles = { - top: this.props.y.toString() + "px", + if (!startPosition) { + return null } - const errorIcon = ( -
- -
- ) + const endPosition = props.bufferToScreen(types.Position.create(lineNumber, endColumn)) - return
{errorIcon}
- } -} + if (!endPosition) { + return null + } -export interface IErrorIconProps { - color: string -} + const pixelStart = props.screenToPixel(startPosition) + const pixelEnd = props.screenToPixel(endPosition) + const pixelWidth = pixelEnd.pixelX - pixelStart.pixelX + const normalizedPixelWidth = pixelWidth === 0 ? props.fontWidthInPixels : pixelWidth + + return ( + + ) + }) -export const ErrorIcon = (props: IErrorIconProps) => { return ( -
- +
+ {markers} + {squiggles}
) } -export interface IErrorSquiggleProps { - x: number +interface IErrorMarkerProps { y: number - height: number - width: number + text: string color: string } -export class ErrorSquiggle extends React.PureComponent { - public render(): JSX.Element { - const { x, y, width, height, color } = this.props +const ErrorMarker = (props: IErrorMarkerProps) => ( + + + +) + +const ErrorMarkerWrapper = withProps<{ topOffset: number }>(styled.div)` + position: absolute; + top: ${props => props.topOffset}px; + right: ${bufferScrollBarSize}; + opacity: 0.5; + background-color: rgb(80, 80, 80); + padding: 4.5px 7px; +` + +interface IErrorIconProps { + color: string +} - const style = { - top: y.toString() + "px", - left: x.toString() + "px", - height: height.toString() + "px", - width: width.toString() + "px", - borderBottom: `1px dashed ${color}`, - } +export const ErrorIcon = (props: IErrorIconProps) => ( + + + +) - return
- } +const IconContainer = withProps<{ color: string }>(styled.div)` + color: ${props => props.color}; +` + +interface IErrorSquiggleProps { + x: number + y: number + height: number + width: number + color: string } +const ErrorSquiggle = withProps(styled.div)` + position: absolute; + ${props => ` + top: ${props.y}px; + left: ${props.x}px; + height: ${props.height}px; + width: ${props.width}px; + border-bottom: 1px dashed ${props.color}; + `} +` From 736e596fa5baf6152c9e352b84226a3a5a7cf01b Mon Sep 17 00:00:00 2001 From: Akin Date: Wed, 4 Apr 2018 18:33:54 +0100 Subject: [PATCH 05/59] Feature/add keyboard binding to browser (#2012) * add commands for bindings * add h,j,k,l scroll bindings * add scrolling commands to browser container and relay via events * change new functions to arrow fns * expose scroll commands for testing [WIP] * add test for scroll functions * improve comments add typing in place of any in test --- browser/src/Input/KeyBindings.ts | 5 ++ browser/src/Services/Browser/BrowserView.tsx | 74 +++++++++++++++- browser/src/Services/Browser/index.tsx | 61 ++++++++++++- ui-tests/BrowserView.test.tsx | 92 ++++++++++++++++++-- 4 files changed, 219 insertions(+), 13 deletions(-) diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index fb26c071b2..e0316ed56d 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -118,4 +118,9 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind(["", ""], "sneak.hide") input.bind("", "sidebar.toggle", isNormalMode) + + input.bind("k", "browser.scrollUp") + input.bind("j", "browser.scrollDown") + input.bind("h", "browser.scrollLeft") + input.bind("l", "browser.scrollRight") } diff --git a/browser/src/Services/Browser/BrowserView.tsx b/browser/src/Services/Browser/BrowserView.tsx index 7e28784e71..f830e0239f 100644 --- a/browser/src/Services/Browser/BrowserView.tsx +++ b/browser/src/Services/Browser/BrowserView.tsx @@ -9,6 +9,7 @@ import * as path from "path" import * as React from "react" import styled from "styled-components" +import { WebviewTag } from "electron" import * as Oni from "oni-api" import { IDisposable, IEvent } from "oni-types" @@ -64,6 +65,10 @@ export interface IBrowserViewProps { goBack: IEvent goForward: IEvent reload: IEvent + scrollUp: IEvent + scrollDown: IEvent + scrollLeft: IEvent + scrollRight: IEvent } export interface IBrowserViewState { @@ -76,7 +81,7 @@ export interface SneakInfoFromBrowser { } export class BrowserView extends React.PureComponent { - private _webviewElement: any + public _webviewElement: WebviewTag private _elem: HTMLElement private _disposables: IDisposable[] = [] @@ -93,13 +98,18 @@ export class BrowserView extends React.PureComponent this._goForward()) const d3 = this.props.reload.subscribe(() => this._reload()) const d4 = this.props.debug.subscribe(() => this._openDebugger()) + const scrollDown = this.props.scrollDown.subscribe(() => this._scrollDown()) + const scrollUp = this.props.scrollUp.subscribe(() => this._scrollUp()) + const scrollRight = this.props.scrollRight.subscribe(() => this._scrollRight()) + const scrollLeft = this.props.scrollLeft.subscribe(() => this._scrollLeft()) const d5 = getSneakInstance().addSneakProvider(async (): Promise => { if (this._webviewElement) { const promise = new Promise(resolve => { this._webviewElement.executeJavaScript( "window['__oni_sneak_collector__']()", - (result: any) => { + null, + result => { resolve(result) }, ) @@ -135,7 +145,18 @@ export class BrowserView extends React.PureComponent + @@ -195,6 +216,50 @@ export class BrowserView extends React.PureComponent { + if (this._webviewElement) { + this._webviewElement.sendInputEvent({ + type: "keyDown", + keyCode: "Left", + canScroll: true, + modifiers: ["isAutoRepeat"], + }) + } + } + + public _scrollRight = (): void => { + if (this._webviewElement) { + this._webviewElement.sendInputEvent({ + type: "keyDown", + keyCode: "Right", + canScroll: true, + modifiers: ["isAutoRepeat"], + }) + } + } + + public _scrollDown = (): void => { + if (this._webviewElement) { + this._webviewElement.sendInputEvent({ + type: "keyDown", + keyCode: "Down", + canScroll: true, + modifiers: ["isAutoRepeat"], + }) + } + } + + public _scrollUp = (): void => { + if (this._webviewElement) { + this._webviewElement.sendInputEvent({ + type: "keyDown", + keyCode: "Up", + canScroll: true, + modifiers: ["isAutoRepeat"], + }) + } + } + private _navigate = (url: string): void => { if (this._webviewElement) { this._webviewElement.src = this.prefixUrl(url) @@ -237,6 +302,7 @@ export class BrowserView extends React.PureComponent() private _goForwardEvent = new Event() private _reloadEvent = new Event() + private _scrollUpEvent = new Event() + private _scrollDownEvent = new Event() + private _scrollRightEvent = new Event() + private _scrollLeftEvent = new Event() constructor(private _url: string, private _configuration: Configuration) {} @@ -41,6 +45,10 @@ export class BrowserLayer implements Oni.BufferLayer { goForward={this._goForwardEvent} reload={this._reloadEvent} debug={this._debugEvent} + scrollDown={this._scrollDownEvent} + scrollUp={this._scrollUpEvent} + scrollLeft={this._scrollLeftEvent} + scrollRight={this._scrollRightEvent} /> ) } @@ -60,6 +68,22 @@ export class BrowserLayer implements Oni.BufferLayer { public reload(): void { this._reloadEvent.dispatch() } + + public scrollUp(): void { + this._scrollUpEvent.dispatch() + } + + public scrollDown(): void { + this._scrollDownEvent.dispatch() + } + + public scrollLeft(): void { + this._scrollLeftEvent.dispatch() + } + + public scrollRight(): void { + this._scrollRightEvent.dispatch() + } } export const activate = ( commandManager: CommandManager, @@ -78,8 +102,9 @@ export const activate = ( }) configuration.registerSetting("browser.zoomFactor", { - description: - "This sets the `zoomFactor` for nested browser windows. A value of `1` means `100%` zoom, a value of 0.5 means `50%` zoom, and a value of `2` means `200%` zoom.", + description: `This sets the "zoomFactor" for nested browser windows. + A value of "1" means "100%" zoom, a value of 0.5 means + "50%" zoom, and a value of "2" means "200%" zoom.`, requiresReload: false, defaultValue: 1, }) @@ -180,6 +205,38 @@ export const activate = ( detail: "", enabled: isBrowserLayerActive, }) + + commandManager.registerCommand({ + command: "browser.scrollDown", + execute: executeCommandForLayer(browser => browser.scrollDown()), + name: "Browser: Scroll Down", + detail: "", + enabled: isBrowserLayerActive, + }) + + commandManager.registerCommand({ + command: "browser.scrollUp", + execute: executeCommandForLayer(browser => browser.scrollUp()), + name: "Browser: Scroll Up", + detail: "", + enabled: isBrowserLayerActive, + }) + + commandManager.registerCommand({ + command: "browser.scrollLeft", + execute: executeCommandForLayer(browser => browser.scrollLeft()), + name: "Browser: Scroll Left", + detail: "", + enabled: isBrowserLayerActive, + }) + + commandManager.registerCommand({ + command: "browser.scrollRight", + execute: executeCommandForLayer(browser => browser.scrollRight()), + name: "Browser: Scroll Right", + detail: "", + enabled: isBrowserLayerActive, + }) } export const registerAchievements = (achievements: AchievementsManager) => { diff --git a/ui-tests/BrowserView.test.tsx b/ui-tests/BrowserView.test.tsx index 9f28ed727a..a406367312 100644 --- a/ui-tests/BrowserView.test.tsx +++ b/ui-tests/BrowserView.test.tsx @@ -1,3 +1,4 @@ +import { WebviewTag } from "electron" import { shallow } from "enzyme" import { shallowToJson } from "enzyme-to-json" import * as React from "react" @@ -11,6 +12,14 @@ import { import { Configuration } from "../browser/src/Services/Configuration" const mockEvent = new Event() +const dispatch = () => mockEvent.dispatch() + +const MockWebviewElement = (spy: (args?: any) => void) => + ({ + sendInputEvent(args) { + spy(args) + }, + } as WebviewTag) // Using the disable life cycle methods here as the CDM calls sneak which is // an external dependency I'm not trying to test here @@ -24,27 +33,96 @@ describe(" Tests", () => { goBack={mockEvent} goForward={mockEvent} reload={mockEvent} + scrollUp={mockEvent} + scrollLeft={mockEvent} + scrollRight={mockEvent} + scrollDown={mockEvent} /> ) + const wrapper = shallow(component, { + disableLifecycleMethods: true, + }) + // can be typed here but the _webviewComponent is expected - TS Error + const instance: any = wrapper.instance() it("component to render correctly", () => { - const wrapper = shallow(component, { disableLifecycleMethods: true }) expect(wrapper).toBeDefined() }) it('Should correctly prefix a url with "https" or "http" if needed', () => { - const wrapper = shallow(component, { disableLifecycleMethods: true }) - // can be typed here but the _webviewComponent is expected - TS Error - const instance: any = wrapper.instance() expect(instance.prefixUrl("apple.com")).toBe("http://apple.com") }) it('Should NOT prefix a url with "https" or "http" if already present', () => { - const wrapper = shallow(component, { disableLifecycleMethods: true }) - const instance: any = wrapper.instance() // subtle difference here as the function always add https as a prefix not http expect(instance.prefixUrl("https://www.apple.com")).toBe("https://www.apple.com") }) it("Should match the recent snapshot - unless an intentional change has occurred ", () => { - const wrapper = shallow(component, { disableLifecycleMethods: true }) expect(shallowToJson(wrapper)).toMatchSnapshot() }) + it("it should call the sendInputEvent method of the mocked webview element on Scroll down", () => { + const typedInstance: BrowserView = instance + const spy = jest.fn() + typedInstance._webviewElement = MockWebviewElement(spy) + typedInstance._scrollDown() + // the spy is passed to the mocked webview element so given that it was called the method accurately + // accessed the method on the webview + expect(spy).toHaveBeenCalled() + const args = { + type: "keyDown", + keyCode: "Down", + canScroll: true, + modifiers: ["isAutoRepeat"], + } + expect(spy.mock.calls[0][0]).toMatchObject(args) + }) + it("it should call the sendInputEvent method of the mocked webview element on Scroll up", () => { + const typedInstance: BrowserView = instance + const spy = jest.fn() + typedInstance._webviewElement = MockWebviewElement(spy) + typedInstance._scrollUp() + // the spy is passed to the mocked webview element so given that it was called the method accurately + // accessed the method on the webview + expect(spy).toHaveBeenCalled() + const args = { + type: "keyDown", + keyCode: "Up", + canScroll: true, + modifiers: ["isAutoRepeat"], + } + expect(spy.mock.calls[0][0]).toMatchObject(args) + }) + it("it should call the sendInputEvent method of the mocked webview element on Scroll left", () => { + const typedInstance: BrowserView = instance + const spy = jest.fn() + typedInstance._webviewElement = MockWebviewElement(spy) + typedInstance._scrollLeft() + expect(spy).toHaveBeenCalled() + const args = { + type: "keyDown", + keyCode: "Left", + canScroll: true, + modifiers: ["isAutoRepeat"], + } + expect(spy.mock.calls[0][0]).toMatchObject(args) + }) + it("it should call the sendInputEvent method of the mocked webview element on Scroll right", () => { + const typedInstance: BrowserView = instance + const spy = jest.fn() + typedInstance._webviewElement = MockWebviewElement(spy) + typedInstance._scrollRight() + expect(spy).toHaveBeenCalled() + const args = { + type: "keyDown", + keyCode: "Right", + canScroll: true, + modifiers: ["isAutoRepeat"], + } + expect(spy.mock.calls[0][0]).toMatchObject(args) + }) + it("it should NOT call the sendInputEvent method if no webview is present", () => { + const typedInstance: BrowserView = instance + const spy = jest.fn() + typedInstance._webviewElement = null + typedInstance._scrollDown() + expect(spy.mock.calls.length).toBe(0) + }) }) From db65022b1217a3e406f45009f1e3a51846c2bae0 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 4 Apr 2018 10:42:46 -0700 Subject: [PATCH 06/59] Bump version to 0.3.3 (#2029) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 08c847881a..2c6ba250f6 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "author": "", "email": "bryphe@outlook.com", "homepage": "https://www.onivim.io", - "version": "0.3.2", + "version": "0.3.3", "description": "Code editor with a modern twist on modal editing - powered by neovim.", "keywords": [ "vim", From 7a924cf553c12df6fe01255a4a4fd0283aba4c35 Mon Sep 17 00:00:00 2001 From: Akin Date: Wed, 4 Apr 2018 22:57:34 +0100 Subject: [PATCH 07/59] add menu command to open new window (#2034) --- browser/src/Services/Commands/GlobalCommands.ts | 4 ++++ browser/src/Services/MultiProcess.ts | 4 ++++ main/src/main.ts | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/browser/src/Services/Commands/GlobalCommands.ts b/browser/src/Services/Commands/GlobalCommands.ts index 1c0a16dfe4..05d6c75cb9 100644 --- a/browser/src/Services/Commands/GlobalCommands.ts +++ b/browser/src/Services/Commands/GlobalCommands.ts @@ -56,6 +56,10 @@ export const activate = ( }), new CallbackCommand("oni.about", null, null, () => showAboutMessage()), + new CallbackCommand("oni.process.openWindow", "New Window", "Open a new window", () => + multiProcess.openNewWindow(), + ), + new CallbackCommand( "oni.editor.maximize", "Maximize Window", diff --git a/browser/src/Services/MultiProcess.ts b/browser/src/Services/MultiProcess.ts index 8ca66f0bed..f2f3c9a8ab 100644 --- a/browser/src/Services/MultiProcess.ts +++ b/browser/src/Services/MultiProcess.ts @@ -19,6 +19,10 @@ export class MultiProcess { public moveToNextOniInstance(direction: string): void { ipcRenderer.send("move-to-next-oni-instance", direction) } + + public openNewWindow(): void { + ipcRenderer.send("open-oni-window") + } } export const activate = (windowManager: WindowManager): void => { diff --git a/main/src/main.ts b/main/src/main.ts index cad7d7112b..3b68a2404a 100644 --- a/main/src/main.ts +++ b/main/src/main.ts @@ -90,6 +90,11 @@ ipcMain.on("move-to-next-oni-instance", (event, direction: string) => { moveToNextOniInstance(windows, direction) }) +ipcMain.on("open-oni-window", () => { + Log.info("opening window") + createWindow([], process.cwd()) +}) + // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let windows: BrowserWindow[] = [] From 2035ae761ebdb7640154782542df32cd94c911ca Mon Sep 17 00:00:00 2001 From: Robin Mehner Date: Thu, 5 Apr 2018 14:39:02 +0200 Subject: [PATCH 08/59] Fix link in README to minimal configuration how to --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6492578496..9f0079d64b 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ And more coming - check out our [Roadmap](https://github.com/onivim/oni/wiki/Roa Oni is cross-platform and supports Windows, Mac, and Linux. -> If you're a Vim power user, and don't need all these features, check out our [minimal configuration](https://github.com/onivim/oni/wiki/How-To:-Minimalist-Oni-Configuration). +> If you're a Vim power user, and don't need all these features, check out our [minimal configuration](https://github.com/onivim/oni/wiki/How-To:-Minimal-Oni-Configuration). ## Installation From ea05be6363681e45ce40c65567452da25b56ac19 Mon Sep 17 00:00:00 2001 From: Himura Kazuto Date: Thu, 5 Apr 2018 21:38:49 +0300 Subject: [PATCH 09/59] Add an example of binding a shortcut to an internal command (#1933) * Add an example of binding to an internal command * Update config.default.js --- configuration/config.default.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configuration/config.default.js b/configuration/config.default.js index ec2ad7b72a..08c4f89dc7 100644 --- a/configuration/config.default.js +++ b/configuration/config.default.js @@ -9,10 +9,11 @@ const activate = oni => { // // Add input bindings here: // + oni.input.bind("", "oni.debug.openDevTools") oni.input.bind("", () => console.log("Control+Enter was pressed")) // - // Or remove the default bindings here by uncommenting the below line: + // Or remove the default bindings: // // oni.input.unbind("") } From f7d4ed1166188fddac4831aa9341fc814be3e943 Mon Sep 17 00:00:00 2001 From: Akin Date: Thu, 5 Apr 2018 21:36:22 +0100 Subject: [PATCH 10/59] Bugfix/syntax highlighting failure post setLines (#2036) * comment out line keeping state dirty as false * check version for updating token rather than line content * fix unit tests.. --- .../SyntaxHighlighting/SyntaxHighlightingReducer.ts | 5 ++++- .../SyntaxHighlighting/SyntaxHighlightingReducerTests.ts | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/browser/src/Services/SyntaxHighlighting/SyntaxHighlightingReducer.ts b/browser/src/Services/SyntaxHighlighting/SyntaxHighlightingReducer.ts index c81a2438d3..d8d3021236 100644 --- a/browser/src/Services/SyntaxHighlighting/SyntaxHighlightingReducer.ts +++ b/browser/src/Services/SyntaxHighlighting/SyntaxHighlightingReducer.ts @@ -134,7 +134,10 @@ export const linesReducer: Reducer = ( const oldLine = updatedBufferState[i] const newLine = action.lines[i] - if (oldLine && oldLine.line === newLine) { + // check if the buffer version has changed and if so + // update the line - rather than check if specific line + // is changed + if (oldLine && oldLine.version >= action.version) { continue } diff --git a/browser/test/Services/SyntaxHighlighting/SyntaxHighlightingReducerTests.ts b/browser/test/Services/SyntaxHighlighting/SyntaxHighlightingReducerTests.ts index be86764b52..de926a04cc 100644 --- a/browser/test/Services/SyntaxHighlighting/SyntaxHighlightingReducerTests.ts +++ b/browser/test/Services/SyntaxHighlighting/SyntaxHighlightingReducerTests.ts @@ -34,19 +34,21 @@ describe("SyntaxHighlightingReducer", () => { }) }) - it("only sets changed lines to dirty", () => { + it("sets lines with a different buffer version to dirty", () => { const originalState: SyntaxHighlighting.SyntaxHighlightLines = { "0": { ruleStack: null, tokens: [], line: "line1", dirty: false, + version: 1, }, "1": { ruleStack: null, tokens: [], line: "line2", dirty: false, + version: 0, }, } @@ -66,6 +68,7 @@ describe("SyntaxHighlightingReducer", () => { tokens: [], line: "line1", dirty: false, + version: 1, }) assert.deepEqual(newState["1"], { @@ -73,6 +76,7 @@ describe("SyntaxHighlightingReducer", () => { tokens: [], line: "line2_update", dirty: true, + version: 0, }) }) }) From 29ae8a55aa82af8c3f8658939af15c8b9619ad2b Mon Sep 17 00:00:00 2001 From: Kevin Forbes Date: Thu, 5 Apr 2018 15:15:10 -0600 Subject: [PATCH 11/59] add Copy and Paste tutorial --- .../src/Services/Learning/Tutorial/Notes.tsx | 36 ++++++- .../Tutorial/Stages/WaitForRegisterStage.tsx | 28 +++++ .../Learning/Tutorial/Stages/index.tsx | 1 + .../Tutorial/Tutorials/CopyPasteTutorial.tsx | 100 ++++++++++++++++++ .../Tutorials/DeleteCharacterTutorial.tsx | 2 +- .../Tutorials/DeleteOperatorTutorial.tsx | 2 +- .../Tutorials/SearchInBufferTutorial.tsx | 2 +- .../Learning/Tutorial/Tutorials/index.tsx | 2 + 8 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 browser/src/Services/Learning/Tutorial/Stages/WaitForRegisterStage.tsx create mode 100644 browser/src/Services/Learning/Tutorial/Tutorials/CopyPasteTutorial.tsx diff --git a/browser/src/Services/Learning/Tutorial/Notes.tsx b/browser/src/Services/Learning/Tutorial/Notes.tsx index 85fcf5ded8..383a21d300 100644 --- a/browser/src/Services/Learning/Tutorial/Notes.tsx +++ b/browser/src/Services/Learning/Tutorial/Notes.tsx @@ -229,7 +229,7 @@ export const DeleteOperatorKey = (): JSX.Element => { keyCharacter="d" description={ - + motion: Deletes text covered by the `motion`. Examples: + + motion: Deletes text specified by a `motion`. Examples: } /> @@ -290,3 +290,37 @@ export const HJKLKeys = (): JSX.Element => { ) } + +export const YankOperatorKey = (): JSX.Element => { + return ( + + + motion: Yanks (copies) text specified by a `motion` + + } + /> + ) +} +export const YankWordKey = (): JSX.Element => { + return ( + Yank to the end of the current word.} + /> + ) +} +export const YankLineKey = (): JSX.Element => { + return ( + Yanks the CURRENT line.} /> + ) +} +export const pasteKey = (): JSX.Element => { + return Paste AFTER the cursor} /> +} +export const PasteKey = (): JSX.Element => { + return ( + Paste BEFORE the cursor} /> + ) +} diff --git a/browser/src/Services/Learning/Tutorial/Stages/WaitForRegisterStage.tsx b/browser/src/Services/Learning/Tutorial/Stages/WaitForRegisterStage.tsx new file mode 100644 index 0000000000..06d18575f3 --- /dev/null +++ b/browser/src/Services/Learning/Tutorial/Stages/WaitForRegisterStage.tsx @@ -0,0 +1,28 @@ +/** + * SetRegisterStage.tsx + * + * Stage that waits for expected register contents + */ + +import { ITutorialContext, ITutorialStage } from "./../ITutorial" + +export class WaitForRegisterStage implements ITutorialStage { + public get goalName(): string { + return this._goal + } + + constructor( + private _goal: string, + private _contents: string, + private _register: string = '"', + ) {} + + public async tickFunction(context: ITutorialContext): Promise { + const contents = await context.editor.neovim.callFunction("getreg", [this._register]) + return contents === this._contents + } + + public render(): JSX.Element { + return null + } +} diff --git a/browser/src/Services/Learning/Tutorial/Stages/index.tsx b/browser/src/Services/Learning/Tutorial/Stages/index.tsx index 61e98de796..259bc822da 100644 --- a/browser/src/Services/Learning/Tutorial/Stages/index.tsx +++ b/browser/src/Services/Learning/Tutorial/Stages/index.tsx @@ -12,6 +12,7 @@ export * from "./InitializeBufferStage" export * from "./MoveToGoalStage" export * from "./SetBufferStage" export * from "./SetCursorPositionStage" +export * from "./WaitForRegisterStage" export * from "./DeleteCharactersStage" export * from "./WaitForModeStage" export * from "./WaitForStateStage" diff --git a/browser/src/Services/Learning/Tutorial/Tutorials/CopyPasteTutorial.tsx b/browser/src/Services/Learning/Tutorial/Tutorials/CopyPasteTutorial.tsx new file mode 100644 index 0000000000..216ee39044 --- /dev/null +++ b/browser/src/Services/Learning/Tutorial/Tutorials/CopyPasteTutorial.tsx @@ -0,0 +1,100 @@ +/** + * CopyPasteTutorial.tsx + * + * Tutorial for learning how to copy and paste text. + */ + +import * as React from "react" + +import { ITutorial, ITutorialMetadata, ITutorialStage } from "./../ITutorial" +import * as Notes from "./../Notes" +import * as Stages from "./../Stages" + +const Line1 = "Like the 'd' operator, 'y' can be used to yank (copy) text" +const Line2 = "Any deleted text or yanked can then be pasted with 'p'" +const Line2YankMarker = "Any deleted ".length +const Line2PasteMarker = "Any deleted text or yanked".length +const Line2PostPaste1 = "Any deleted text or yanked text can then be pasted with 'p'" +const Line2PostPaste2 = "text Any deleted text or yanked text can then be pasted with 'p'" +const Line1PostTranspose = "iLke the 'd' operator, 'y' can be used to yank (copy) text" + +export class CopyPasteTutorial implements ITutorial { + private _stages: ITutorialStage[] + + constructor() { + this._stages = [ + new Stages.SetBufferStage([Line1, Line2]), + new Stages.MoveToGoalStage("Move to the word 'text'", 1, Line2YankMarker), + new Stages.WaitForRegisterStage("Yank this word with 'yw'", "text "), + new Stages.MoveToGoalStage("Move after the word 'yanked'", 1, Line2PasteMarker), + new Stages.WaitForStateStage("Paste after the cursor with 'p'", [ + Line1, + Line2PostPaste1, + ]), + new Stages.MoveToGoalStage("Move to the beginning of the line", 1, 0), + new Stages.WaitForStateStage("Paste before the cursor with 'P'", [ + Line1, + Line2PostPaste2, + ]), + new Stages.WaitForRegisterStage( + "Yank the entire line with 'yy'", + Line2PostPaste2 + "\n", + ), + new Stages.WaitForStateStage("Paste the yanked line below the cursor with 'p'", [ + Line1, + Line2PostPaste2, + Line2PostPaste2, + ]), + new Stages.MoveToGoalStage("Move to the top of the file", 0, 0), + new Stages.WaitForStateStage("Paste _above_ the cursor with 'P'", [ + Line2PostPaste2, + Line1, + Line2PostPaste2, + Line2PostPaste2, + ]), + new Stages.MoveToGoalStage("Move to the next line", 1, 0), + new Stages.WaitForStateStage("Deleting also copies text. Delete a line with 'dd'", [ + Line2PostPaste2, + Line2PostPaste2, + Line2PostPaste2, + ]), + new Stages.WaitForStateStage("Again, paste with 'p'", [ + Line2PostPaste2, + Line2PostPaste2, + Line1, + Line2PostPaste2, + ]), + new Stages.WaitForStateStage( + "Since deleted text is also copied, transposing characters is simple. Try 'xp'", + [Line2PostPaste2, Line2PostPaste2, Line1PostTranspose, Line2PostPaste2], + ), + ] + } + + public get metadata(): ITutorialMetadata { + return { + id: "oni.tutorials.copy_paste", + name: "Copy & Paste: y, p", + description: + 'Now that you know about operators and motions pairing like a noun and a verb, we can start learning new operators. The `y` operator can be used to copy ("yank") text which can then be pasted with `p`. Using `p` pastes _after_ the cursor, and `P` pastes _before_ the cursor. The `y` operator behaves just like the `d` operator and can be paired with any motion.', + level: 210, + } + } + + public get stages(): ITutorialStage[] { + return this._stages + } + + public get notes(): JSX.Element[] { + return [ + , + , + , + , + , + , + , + , + ] + } +} diff --git a/browser/src/Services/Learning/Tutorial/Tutorials/DeleteCharacterTutorial.tsx b/browser/src/Services/Learning/Tutorial/Tutorials/DeleteCharacterTutorial.tsx index da06302ae4..cd4b29c4e9 100644 --- a/browser/src/Services/Learning/Tutorial/Tutorials/DeleteCharacterTutorial.tsx +++ b/browser/src/Services/Learning/Tutorial/Tutorials/DeleteCharacterTutorial.tsx @@ -131,7 +131,7 @@ export class DeleteCharacterTutorial implements ITutorial { name: "Deleting a Character", description: "In normal mode, you can quickly delete characters. Move to the character (using h/j/k/l) and press `x` to delete. Correct the above lines without going to insert mode.", - level: 120, + level: 190, } } diff --git a/browser/src/Services/Learning/Tutorial/Tutorials/DeleteOperatorTutorial.tsx b/browser/src/Services/Learning/Tutorial/Tutorials/DeleteOperatorTutorial.tsx index 5d5188735e..2fc4d07ccf 100644 --- a/browser/src/Services/Learning/Tutorial/Tutorials/DeleteOperatorTutorial.tsx +++ b/browser/src/Services/Learning/Tutorial/Tutorials/DeleteOperatorTutorial.tsx @@ -85,7 +85,7 @@ export class DeleteOperatorTutorial implements ITutorial { name: "Delete Operator: d", description: "We've stuck mostly with motions, but now we're going to learn about our first operator - delete (`d`). Operators are like _verbs_ in the vim world, and motions are like _nouns_. An operator can be paired with a motion - which means we can pair the `d` key with all sorts of motions - `dj` to delete the line and the line below, `dw` to delete a word, etc.", - level: 180, + level: 200, } } diff --git a/browser/src/Services/Learning/Tutorial/Tutorials/SearchInBufferTutorial.tsx b/browser/src/Services/Learning/Tutorial/Tutorials/SearchInBufferTutorial.tsx index 3bbf9554ad..0511ae155f 100644 --- a/browser/src/Services/Learning/Tutorial/Tutorials/SearchInBufferTutorial.tsx +++ b/browser/src/Services/Learning/Tutorial/Tutorials/SearchInBufferTutorial.tsx @@ -67,7 +67,7 @@ export class SearchInBufferTutorial implements ITutorial { name: "Motion: /, ?, n, N", description: "To navigate a buffer efficiently, Oni lets you search for strings with `/` and `?`. `n` and `N` let you navigate quickly between the matches!", - level: 190, + level: 180, } } diff --git a/browser/src/Services/Learning/Tutorial/Tutorials/index.tsx b/browser/src/Services/Learning/Tutorial/Tutorials/index.tsx index bbe5be06d4..95c3489904 100644 --- a/browser/src/Services/Learning/Tutorial/Tutorials/index.tsx +++ b/browser/src/Services/Learning/Tutorial/Tutorials/index.tsx @@ -13,6 +13,7 @@ import { SearchInBufferTutorial } from "./SearchInBufferTutorial" import { SwitchModeTutorial } from "./SwitchModeTutorial" import { VerticalMovementTutorial } from "./VerticalMovementTutorial" import { WordMotionTutorial } from "./WordMotionTutorial" +import { CopyPasteTutorial } from "./CopyPasteTutorial" export * from "./DeleteCharacterTutorial" export * from "./SwitchModeTutorial" @@ -27,4 +28,5 @@ export const AllTutorials: ITutorial[] = [ new VerticalMovementTutorial(), new WordMotionTutorial(), new SearchInBufferTutorial(), + new CopyPasteTutorial(), ] From 92b6555ffa9e6cbdccc1ef2a624689ee6e6057a0 Mon Sep 17 00:00:00 2001 From: Kevin Forbes Date: Thu, 5 Apr 2018 15:18:27 -0600 Subject: [PATCH 12/59] alphabetize import list --- browser/src/Services/Learning/Tutorial/Tutorials/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/Services/Learning/Tutorial/Tutorials/index.tsx b/browser/src/Services/Learning/Tutorial/Tutorials/index.tsx index 95c3489904..1f679b8785 100644 --- a/browser/src/Services/Learning/Tutorial/Tutorials/index.tsx +++ b/browser/src/Services/Learning/Tutorial/Tutorials/index.tsx @@ -6,6 +6,7 @@ import { ITutorial } from "./../ITutorial" import { BasicMovementTutorial } from "./BasicMovementTutorial" import { BeginningsAndEndingsTutorial } from "./BeginningsAndEndingsTutorial" +import { CopyPasteTutorial } from "./CopyPasteTutorial" import { DeleteCharacterTutorial } from "./DeleteCharacterTutorial" import { DeleteOperatorTutorial } from "./DeleteOperatorTutorial" import { MoveAndInsertTutorial } from "./MoveAndInsertTutorial" @@ -13,7 +14,6 @@ import { SearchInBufferTutorial } from "./SearchInBufferTutorial" import { SwitchModeTutorial } from "./SwitchModeTutorial" import { VerticalMovementTutorial } from "./VerticalMovementTutorial" import { WordMotionTutorial } from "./WordMotionTutorial" -import { CopyPasteTutorial } from "./CopyPasteTutorial" export * from "./DeleteCharacterTutorial" export * from "./SwitchModeTutorial" From 820af10d689ac86df15c1aca8d4c53b6d72c5783 Mon Sep 17 00:00:00 2001 From: Samuel Doiron Date: Thu, 5 Apr 2018 22:48:51 -0300 Subject: [PATCH 13/59] Implement scroll delta threshold to improve macOS scrolling experience. (#2042) * Add type annotations to CSS declarations Without these declarations, typescript was infering the types of some literal values (eg. `"visible"`) as having type `string`. Declaring the type as React.CSSProperties corrects this. * Add a delta threshold for scroll events Scroll events are emitted very frequently on macOS. Previously, we were moving a single line on every scroll event, which made scrolling on macOS way too fast. The value `100` is taken from Windows measurements given here: https://gist.github.com/bryphe/43caa81bbec16d90d7b47f084014774b * Move scroll threshold to constant * Account for WheelEvent.deltaMode during scrolling The delta values given on `WheelEvent`s can sometimes be measured in units other than pixels. --- browser/src/Input/Mouse.ts | 40 +++++++++++++++---- .../src/UI/components/CursorPositioner.tsx | 2 +- browser/src/UI/components/WindowTitle.tsx | 2 +- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/browser/src/Input/Mouse.ts b/browser/src/Input/Mouse.ts index 1ec9df5645..6e1c2b3dc5 100644 --- a/browser/src/Input/Mouse.ts +++ b/browser/src/Input/Mouse.ts @@ -2,10 +2,13 @@ import { EventEmitter } from "events" import { IScreen } from "./../neovim" +const SCROLL_THRESHOLD_IN_PIXELS = 100 + // TODO // Handle modifier keys export class Mouse extends EventEmitter { private _isDragging = false + private _scrollDelta = 0 constructor(private _editorElement: HTMLDivElement, private _screen: IScreen) { super() @@ -40,22 +43,41 @@ export class Mouse extends EventEmitter { scrollcmdY += `C-` // The S- and C- prefixes have the same effect } - // This is 'less than' because I made this on a mac to behave just like - // the other applications I use. However, because OSX is super weird, it - // might be backwards - if (evt.deltaY) { - if (evt.deltaY < 0) { + const normalizedDelta = this._normalizeScrollDeltaToPixels(evt.deltaY, evt.deltaMode) + if (!normalizedDelta) { + return + } + + this._isDragging = false + this._scrollDelta += normalizedDelta + if (this._scrollDeltaIsSignificant()) { + // This is 'less than' because I made this on a mac to behave just like + // the other applications I use. However, because OSX is super weird, it + // might be backwards. + if (this._scrollDelta < 0) { scrollcmdY += `ScrollWheelUp>` } else { scrollcmdY += `ScrollWheelDown>` } + this._scrollDelta = 0 this.emit("mouse", scrollcmdY + `<${line},${column}>`) } - - this._isDragging = false }) } + private _normalizeScrollDeltaToPixels(delta: number, deltaMode: number): number { + switch (deltaMode) { + case WheelEvent.DOM_DELTA_PIXEL: + return delta + case WheelEvent.DOM_DELTA_LINE: + return delta * this._screen.fontHeightInPixels + case WheelEvent.DOM_DELTA_PAGE: + return delta * this._screen.fontHeightInPixels * this._screen.height + default: + return delta + } + } + private _convertEventToPosition(evt: MouseEvent): { line: number; column: number } { const mouseX = evt.offsetX const mouseY = evt.offsetY @@ -65,4 +87,8 @@ export class Mouse extends EventEmitter { column: Math.floor(mouseY / this._screen.fontHeightInPixels), } } + + private _scrollDeltaIsSignificant(): boolean { + return Math.abs(this._scrollDelta) >= SCROLL_THRESHOLD_IN_PIXELS + } } diff --git a/browser/src/UI/components/CursorPositioner.tsx b/browser/src/UI/components/CursorPositioner.tsx index eba0852de6..3adb1128c5 100644 --- a/browser/src/UI/components/CursorPositioner.tsx +++ b/browser/src/UI/components/CursorPositioner.tsx @@ -152,7 +152,7 @@ export class CursorPositionerView extends React.PureComponent< const childStyle = this.state.shouldOpenDownward ? openFromTopStyle : openFromBottomStyle const arrowStyle = this.state.shouldOpenDownward ? openFromBottomStyle : openFromTopStyle - const arrowStyleWithAdjustments = { + const arrowStyleWithAdjustments: React.CSSProperties = { ...arrowStyle, left: (this.props.x + this.props.fontPixelWidth / 2).toString() + "px", visibility: this.props.hideArrow ? "hidden" : "visible", diff --git a/browser/src/UI/components/WindowTitle.tsx b/browser/src/UI/components/WindowTitle.tsx index bd5b8c2c2a..824bfaaa40 100644 --- a/browser/src/UI/components/WindowTitle.tsx +++ b/browser/src/UI/components/WindowTitle.tsx @@ -24,7 +24,7 @@ export class WindowTitleView extends React.PureComponent Date: Fri, 6 Apr 2018 07:44:57 +0100 Subject: [PATCH 14/59] Feature: Prettier plugin (#1540) * Add initial implementation of prettier plugin * add config options to test using config functionality * update config to allow disabling, add status icon * comment out console.log add check if code is formatted add initial attempt at cursor position * fix config to camelcase * add assets for prettier icon * add line column and [wip] attempt to return correct cursor pos * fix cursor positioning * Remove linecolumn, not working remove prettier asset more work on cursor positioning add success and error status icons * update yarn lock * Fix eslintrc add allowedFiletypes checking * add onClick fn to prettier element add allowedFiletypes option to config * remove console.logs * add convert offset function and get cursor offset function * use vim based byte offset or prettier * remove unused dependencies * add install command or prettier plugin * add install command to plugins command * update dir or prettier plugin * relocate prettier plugin to correct dir * add filepath for parser inference and change icon * remove extra CR added on joining string * add printWidth option and add graphql to default fts * fix print width use number * add editor config option add buffer state to track if modified add icon colors * remove console.log * conditionally render prettier status item * minor change to rerun tests * [WIP] Add prettier-plugin test * [WIP] comment out test while attempting to test prettier plugin\ * comment out non-functional tests * re-add commented tests, deactivate prettier test * Tweak prettier plugin architecture for tests * comment out ci tests and contiue work on prettier test * fix config for test, update test [WIP] * add functioning ci test for prettier * ensure existence of prettier status item * add helper functions to common add new [wip] ci test * refactor get cursor offset to a get method make convertCursorPos zero base to march getCursorPos * add new bufferCursorTest file * fix missing CI test and remove redundant calc * remove redundant methods from prettier test * tweak function to keep state within function rather than globally move failing windows test to bottom to see if only that test fails * remove specific use of newline per platform * switch to a more functional approach slightly excessive for now but a foundation for further tweaks in the ongoing development of this plugin * fix prettier callback to use new state tracking version switch to function keyword to ensure applyprettier is hoisted so callback can reference it * fix typo and add check in prettier rc function * use prettier info to poplulate compatible filetypes * fix incorrect ref to config * actually remove incorrect conffig ref --- browser/src/Editor/BufferManager.ts | 26 ++- .../Configuration/DefaultConfiguration.ts | 16 ++ .../Configuration/IConfigurationValues.ts | 18 ++ extensions/oni-plugin-prettier/.eslintrc.json | 45 ++++ extensions/oni-plugin-prettier/index.js | 201 ++++++++++++++++++ extensions/oni-plugin-prettier/package.json | 18 ++ package.json | 3 +- test/CiTests.ts | 2 + test/ci/Common.ts | 14 ++ test/ci/Editor.BuffersCursorTest.ts | 37 ++++ test/ci/MarkdownPreviewTest.tsx | 16 +- test/ci/PrettierPluginTest.ts | 88 ++++++++ vim/core/oni-core-interop/plugin/init.vim | 2 +- 13 files changed, 465 insertions(+), 21 deletions(-) create mode 100644 extensions/oni-plugin-prettier/.eslintrc.json create mode 100644 extensions/oni-plugin-prettier/index.js create mode 100644 extensions/oni-plugin-prettier/package.json create mode 100644 test/ci/Editor.BuffersCursorTest.ts create mode 100644 test/ci/PrettierPluginTest.ts diff --git a/browser/src/Editor/BufferManager.ts b/browser/src/Editor/BufferManager.ts index 92d2f64853..0e00aa57e2 100644 --- a/browser/src/Editor/BufferManager.ts +++ b/browser/src/Editor/BufferManager.ts @@ -88,6 +88,7 @@ export class Buffer implements IBuffer { private _filePath: string private _language: string private _cursor: Oni.Cursor + private _cursorOffset: number private _version: number private _modified: boolean private _lineCount: number @@ -111,6 +112,10 @@ export class Buffer implements IBuffer { return this._cursor } + public get cursorOffset(): number { + return this._cursorOffset + } + public get version(): number { return this._version } @@ -146,6 +151,18 @@ export class Buffer implements IBuffer { this._actions.removeBufferLayer(parseInt(this._id, 10), layer) } + /** + * convertOffsetToLineColumn + */ + public async convertOffsetToLineColumn( + cursorOffset = this._cursorOffset, + ): Promise { + const line: number = await this._neovimInstance.callFunction("byte2line", [cursorOffset]) + const countFromLine: number = await this._neovimInstance.callFunction("line2byte", [line]) + const column = cursorOffset - countFromLine + return types.Position.create(line - 1, column) + } + public async getCursorPosition(): Promise { const pos = await this._neovimInstance.callFunction("getpos", ["."]) const [, oneBasedLine, oneBasedColumn] = pos @@ -213,10 +230,10 @@ export class Buffer implements IBuffer { const bufferLinesPromise = this.getLines(0, 1024) const detectIndentPromise = import("detect-indent") - await Promise.all([bufferLinesPromise, detectIndentPromise]) - - const bufferLines = await bufferLinesPromise - const detectIndent = await detectIndentPromise + const [bufferLines, detectIndent] = await Promise.all([ + bufferLinesPromise, + detectIndentPromise, + ]) const ret = detectIndent(bufferLines.join("\n")) @@ -414,6 +431,7 @@ export class Buffer implements IBuffer { this._version = evt.version this._modified = evt.modified this._lineCount = evt.bufferTotalLines + this._cursorOffset = evt.byte this._cursor = { line: evt.line - 1, diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 2512bf1bc2..42f745c7dc 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -262,6 +262,22 @@ const BaseConfiguration: IConfigurationValues = { "oni.status.git": 3, }, + "oni.plugins.prettier": { + settings: { + semi: false, + tabWidth: 2, + useTabs: false, + singleQuote: false, + trailingComma: "es5", + bracketSpacing: true, + jsxBracketSameLine: false, + arrowParens: "avoid", + printWidth: 80, + }, + formatOnSave: false, + enabled: false, + }, + "tabs.mode": "tabs", "tabs.height": "2.5em", "tabs.highlight": true, diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index 98dcbcab83..a9057af45d 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -227,6 +227,24 @@ export interface IConfigurationValues { "sidebar.marks.enabled": boolean "sidebar.plugins.enabled": boolean + "oni.plugins.prettier": { + settings: { + semi: boolean + tabWidth: number + useTabs: boolean + singleQuote: boolean + trailingComma: "es5" | "all" | "none" + bracketSpacing: boolean + jsxBracketSameLine: boolean + arrowParens: "avoid" | "always" + printWidth: number + [key: string]: number | string | boolean + } + formatOnSave: boolean + enabled: boolean + allowedFiletypes?: string[] + } + "snippets.enabled": boolean "snippets.userSnippetFolder": string diff --git a/extensions/oni-plugin-prettier/.eslintrc.json b/extensions/oni-plugin-prettier/.eslintrc.json new file mode 100644 index 0000000000..ccd62afc2c --- /dev/null +++ b/extensions/oni-plugin-prettier/.eslintrc.json @@ -0,0 +1,45 @@ +{ + "rules": { + "indent": 0, + "linebreak-style": ["off", "unix"], + "quotes": ["error", "double", { "allowTemplateLiterals": true }], + "semi": ["error", "never"], + "array-callback-return": "error", + "eqeqeq": "error", + "no-console": "on", + "strict": 0, + "no-unused-vars": 0, + "no-undef": 1, + "no-undefined": 1, + "camelcase": 1, + "no-underscore-dangle": 0, + "no-console": 0, + "no-invalid-this": 1, + "no-useless-return": 1, + "comma-dangle": ["error", "only-multiline"], + "comma-spacing": ["error", { "before": false, "after": true }] + }, + "env": { + "es6": true, + "browser": true, + "jasmine": true, + "mocha": true + }, + "settings": { + "ecmascript": 6, + "jsx": true + }, + "extends": "eslint:recommended", + "parser": "babel-eslint", + "plugins": ["react"], + "globals": { + "_": false, + "remote": false, + "process": false, + "module": false, + "require": false, + "__dirname": false, + "preloadedData": false + }, + "root": true +} diff --git a/extensions/oni-plugin-prettier/index.js b/extensions/oni-plugin-prettier/index.js new file mode 100644 index 0000000000..7836cbdf7e --- /dev/null +++ b/extensions/oni-plugin-prettier/index.js @@ -0,0 +1,201 @@ +const path = require("path") +const prettier = require("prettier") + +// Helper functions +const compose = (...fns) => argument => fns.reduceRight((arg, fn) => fn(arg), argument) +const joinOrSplit = (method, by = "\n") => array => array[method](by) +const join = joinOrSplit("join") +const split = joinOrSplit("split") +const isEqual = toCompare => initialItem => initialItem === toCompare +const isTrue = (...args) => args.every(a => Boolean(a)) +const eitherOr = (...args) => args.find(a => !!a) +const flatten = multidimensional => [].concat(...multidimensional) + +const isCompatible = (allowedFiletypes, defaultFiletypes) => filePath => { + const filetypes = isTrue(allowedFiletypes, Array.isArray(allowedFiletypes)) + ? allowedFiletypes + : defaultFiletypes + const extension = path.extname(filePath) + return filetypes.includes(extension) +} + +const getSupportedLanguages = async () => { + const info = await prettier.getSupportInfo() + return flatten(info.languages.map(lang => lang.extensions)) +} + +const activate = async Oni => { + const config = Oni.configuration.getValue("oni.plugins.prettier") + const prettierItem = Oni.statusBar.createItem(0, "oni.plugins.prettier") + + const applyPrettierWithState = applyPrettier() + const defaultFiletypes = await getSupportedLanguages() + + const callback = async () => { + const isNormalMode = Oni.editors.activeEditor.mode === "normal" + if (isNormalMode) { + await applyPrettierWithState(Oni) + } + } + Oni.commands.registerCommand({ + command: "autoformat.prettier", + name: "Autoformat with Prettier", + execute: callback, + }) + + const checkPrettierrc = async bufferPath => { + if (!bufferPath) { + throw new Error(`No buffer path passed for prettier to check for a Prettierrc`) + } + try { + return await prettier.resolveConfig(bufferPath) + } catch (e) { + throw new Error(`Error parsing config file, ${e}`) + } + } + + // Status Bar Component ---- + const { errorElement, successElement, prettierElement } = createPrettierComponent(Oni, callback) + + prettierItem.setContents(prettierElement) + + const setStatusBarContents = (statusBarItem, defaultElement) => async ( + statusElement, + timeOut = 3500, + ) => { + statusBarItem.setContents(statusElement) + await setTimeout(() => statusBarItem.setContents(defaultElement), timeOut) + } + + const setPrettierStatus = setStatusBarContents(prettierItem, prettierElement) + + function applyPrettier() { + // Track the buffer state within the function using a closure + // if the buffer as a string is the same as the last state + // do no format because nothing has changed + let lastBufferState = null + + // pass in Oni explicitly - Make dependencies clearer + return async Oni => { + const { activeBuffer } = Oni.editors.activeEditor + + const [arrayOfLines, { line, character }] = await Promise.all([ + activeBuffer.getLines(), + activeBuffer.getCursorPosition(), + ]) + + const hasNotChanged = compose(isEqual(lastBufferState), join) + + if (hasNotChanged(arrayOfLines)) { + return + } + + try { + const prettierrc = await checkPrettierrc(activeBuffer.filePath) + const prettierConfig = eitherOr(prettierrc, config.settings) + + // Pass in the file path so prettier can infer the correct parser to use + const { formatted, cursorOffset } = prettier.formatWithCursor( + join(arrayOfLines), + Object.assign({ filepath: activeBuffer.filePath }, prettierConfig, { + cursorOffset: activeBuffer.cursorOffset, + }), + ) + if (!formatted) { + throw new Error("Couldn't format the buffer") + } + + await setPrettierStatus(successElement) + + const withoutFinalCR = formatted.replace(/\n$/, "") + lastBufferState = withoutFinalCR + + const [, { character, line }] = await Promise.all([ + activeBuffer.setLines(0, arrayOfLines.length, split(withoutFinalCR)), + activeBuffer.convertOffsetToLineColumn(cursorOffset), + ]) + + await activeBuffer.setCursorPosition(line, character) + await Oni.editors.activeEditor.neovim.command("w") + } catch (e) { + console.warn(`Couldn't format the buffer because: ${e}`) + await setPrettierStatus(errorElement) + } + } + } + + const { allowedFiletypes, formatOnSave, enabled } = config + const checkCompatibility = isCompatible(allowedFiletypes, defaultFiletypes) + + Oni.editors.activeEditor.onBufferEnter.subscribe(({ filePath }) => { + const hasCompatibility = checkCompatibility(filePath) + + hasCompatibility ? prettierItem.show() : prettierItem.hide() + }) + + Oni.editors.activeEditor.onBufferSaved.subscribe(async ({ filePath }) => { + const hasCompatibility = checkCompatibility(filePath) + + const canApplyPrettier = isTrue(formatOnSave, enabled, hasCompatibility) + if (canApplyPrettier) { + await applyPrettierWithState(Oni) + } + }) + return { applyPrettier: applyPrettierWithState, checkCompatibility, checkPrettierrc } +} + +function createPrettierComponent(Oni, onClick) { + const { React } = Oni.dependencies + + const background = Oni.colors.getColor("highlight.mode.normal.background") + const foreground = Oni.colors.getColor("highlight.mode.normal.foreground") + const style = { + width: "100%", + height: "100%", + display: "flex", + alignItems: "center", + justifyContent: "center", + paddingLeft: "8px", + paddingRight: "8px", + color: "white", + backgroundColor: foreground, + } + + const prettierIcon = (type = "magic") => + Oni.ui.createIcon({ + name: type, + size: Oni.ui.iconSize.Default, + }) + + const iconContainer = (type, color = "white") => + React.createElement("div", { style: { padding: "0 6px 0 0", color } }, prettierIcon(type)) + + const prettierElement = React.createElement( + "div", + { className: "prettier", style, onClick }, + iconContainer(), + "prettier", + ) + + const errorElement = React.createElement( + "div", + { style, className: "prettier" }, + iconContainer("exclamation-triangle", "yellow"), + "prettier", + ) + + const successElement = React.createElement( + "div", + { style, className: "prettier" }, + iconContainer("check", "#5AB379"), + "prettier", + ) + + return { + errorElement, + prettierElement, + successElement, + } +} + +module.exports = { activate } diff --git a/extensions/oni-plugin-prettier/package.json b/extensions/oni-plugin-prettier/package.json new file mode 100644 index 0000000000..a4dfce72e7 --- /dev/null +++ b/extensions/oni-plugin-prettier/package.json @@ -0,0 +1,18 @@ +{ + "name": "oni-plugin-prettier", + "version": "1.0.0", + "main": "index.js", + "engines": { + "oni": "^0.2.6" + }, + "scripts": {}, + "oni": { + "supportedFileTypes": [ + "*" + ] + }, + "dependencies": { + "prettier": "^1.11.1" + }, + "devDependencies": {} +} diff --git a/package.json b/package.json index 2c6ba250f6..fb7e402460 100644 --- a/package.json +++ b/package.json @@ -838,8 +838,9 @@ "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": "npm run install:plugins:oni-plugin-markdown-preview && npm run install:plugins:oni-plugin-prettier", "install:plugins:oni-plugin-markdown-preview": "cd extensions/oni-plugin-markdown-preview && npm install --prod", + "install:plugins:oni-plugin-prettier": "cd extensions/oni-plugin-prettier && 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" }, diff --git a/test/CiTests.ts b/test/CiTests.ts index 31b3f0efff..43540a05c1 100644 --- a/test/CiTests.ts +++ b/test/CiTests.ts @@ -22,12 +22,14 @@ const CiTests = [ "Configuration.TypeScriptEditor.NewConfigurationTest", "Configuration.TypeScriptEditor.CompletionTest", + "Editor.BuffersCursorTest", "Editor.ExternalCommandLineTest", "Editor.BufferModifiedState", "Editor.OpenFile.PathWithSpacesTest", "Editor.TabModifiedState", "Editor.CloseTabWithTabModesTabsTest", "MarkdownPreviewTest", + "PrettierPluginTest", "PaintPerformanceTest", "QuickOpenTest", "StatusBar-Mode", diff --git a/test/ci/Common.ts b/test/ci/Common.ts index d70f00c49b..1c6edb2637 100644 --- a/test/ci/Common.ts +++ b/test/ci/Common.ts @@ -74,3 +74,17 @@ export const waitForCommand = async (command: string, oni: Oni.Plugin.Api): Prom return anyCommands.hasCommand(command) }, 10000) } + +export async function awaitEditorMode(oni: Oni.Plugin.Api, mode: string): Promise { + function condition(): boolean { + return oni.editors.activeEditor.mode === mode + } + await oni.automation.waitFor(condition) +} + +export 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") +} diff --git a/test/ci/Editor.BuffersCursorTest.ts b/test/ci/Editor.BuffersCursorTest.ts new file mode 100644 index 0000000000..70bff114cb --- /dev/null +++ b/test/ci/Editor.BuffersCursorTest.ts @@ -0,0 +1,37 @@ +/* + * Test Cursor functionality of oni buffers + * + */ +import * as assert from "assert" +import * as Oni from "oni-api" + +import { createNewFile, getTemporaryFilePath, insertText, navigateToFile } from "./Common" + +export const test = async (oni: Oni.Plugin.Api) => { + await oni.automation.waitForEditors() + + createNewFile("ts", oni) + await insertText(oni, "console.log('apple')") + + const activeBuffer: any = oni.editors.activeEditor.activeBuffer + + const { cursorOffset } = activeBuffer + + assert.equal(cursorOffset, 20) + + // Test that a cursor offset is correctly converted to a line and character + // results are 0 based + const { line, character } = await activeBuffer.convertOffsetToLineColumn(cursorOffset) + + assert.equal(line, 0) + assert.equal(character, 19) + // Check that the cursor position from the conversion matches the getCursorPosition method + // results + const { + line: currentLine, + character: currentCharacter, + } = await activeBuffer.getCursorPosition() + + assert.strictEqual(line, currentLine) + assert.strictEqual(currentCharacter, character) +} diff --git a/test/ci/MarkdownPreviewTest.tsx b/test/ci/MarkdownPreviewTest.tsx index bd5a5330c2..fcaf6e83e1 100644 --- a/test/ci/MarkdownPreviewTest.tsx +++ b/test/ci/MarkdownPreviewTest.tsx @@ -3,7 +3,7 @@ */ import { Assertor } from "./Assert" -import { getTemporaryFilePath, navigateToFile } from "./Common" +import { awaitEditorMode, getTemporaryFilePath, insertText, navigateToFile } from "./Common" import * as Oni from "oni-api" @@ -46,17 +46,3 @@ export async function test(oni: Oni.Plugin.Api) { "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") -} diff --git a/test/ci/PrettierPluginTest.ts b/test/ci/PrettierPluginTest.ts new file mode 100644 index 0000000000..573a6b1e56 --- /dev/null +++ b/test/ci/PrettierPluginTest.ts @@ -0,0 +1,88 @@ +/** + * Test the Prettier plugin + */ + +import * as stock_assert from "assert" +import * as os from "os" +import { Assertor } from "./Assert" +import { + awaitEditorMode, + createNewFile, + getElementByClassName, + getTemporaryFilePath, + insertText, +} from "./Common" + +import * as Oni from "oni-api" + +interface IPluginManager { + getPlugin(name: string): any +} + +interface IPrettierPlugin { + checkCompatibility(filePath: string): boolean + applyPrettier(): void + checkPrettierrc(): boolean +} + +export const settings = { + config: { + "oni.useDefaultConfig": true, + "oni.loadInitVim": false, + "oni.plugins.prettier": { + settings: { + semi: false, + tabWidth: 2, + useTabs: false, + singleQuote: false, + trailingComma: "es5", + bracketSpacing: true, + jsxBracketSameLine: false, + arrowParens: "avoid", + printWidth: 80, + }, + formatOnSave: true, + enabled: true, + allowedFiletypes: [".js", ".jsx", ".ts", ".tsx", ".md", ".html", ".json", ".graphql"], + }, + }, +} + +export async function test(oni: Oni.Plugin.Api) { + const assert = new Assertor("Prettier-plugin") + + await oni.automation.waitForEditors() + await createNewFile("ts", oni) + + await insertText(oni, "function test(){console.log('test')};") + + await oni.automation.waitFor(() => oni.plugins.loaded) + + // Test that the prettier status bar item is present + const prettierElement = getElementByClassName("prettier") + assert.defined(prettierElement, "Prettier status icon element is present") + + const prettierPlugin: IPrettierPlugin = await oni.plugins.getPlugin("oni-plugin-prettier") + assert.defined(prettierPlugin, "plugin instance") + assert.defined(prettierPlugin.applyPrettier, "plugin formatting method") + + const { activeBuffer } = oni.editors.activeEditor + assert.assert( + prettierPlugin.checkCompatibility(activeBuffer.filePath), + "If valid filetype prettier plugin check should return true", + ) + + // Test that in a Typescript file the plugin formats the buffer on save + oni.automation.sendKeys("0") + oni.automation.sendKeys(":") + oni.automation.sendKeys("w") + oni.automation.sendKeys("") + + await oni.automation.sleep(5000) + + const bufferText = await activeBuffer.getLines() + const bufferString = bufferText.join(os.EOL) + assert.assert(!bufferString.includes(";"), "Semi colons are removed from the text") + assert.assert(!bufferString.includes("'"), "Single quotes are removed from the formatted text") + assert.assert(bufferText.length === 3, "The code is split into 3 lines") +} diff --git a/vim/core/oni-core-interop/plugin/init.vim b/vim/core/oni-core-interop/plugin/init.vim index 2eb1b66ac4..1631a77040 100644 --- a/vim/core/oni-core-interop/plugin/init.vim +++ b/vim/core/oni-core-interop/plugin/init.vim @@ -167,7 +167,7 @@ let context.windowTopLine = line("w0") let context.windowBottomLine = line("w$") let context.windowWidth = winwidth(winnr()) let context.windowHeight = winheight(winnr()) -let context.byte = line2byte(line(".")) + col(".") +let context.byte = line2byte (line ( "." ) ) + col ( "." ) - 1 let context.filetype = eval("&filetype") let context.modified = &modified let context.hidden = &hidden From afab2beac8c9374db9996118d1892e2bf074275d Mon Sep 17 00:00:00 2001 From: Ryan C Date: Fri, 6 Apr 2018 10:54:21 +0100 Subject: [PATCH 15/59] Add VSCode QuickOpen Scoring/Sorting (#2009) * Add VSCode files for now. * Hook up to current regex method. * Fix or ignore lint issues. * Swap to using scoreItem and add Oni wrapper. * Hook up highlighting to VSCode results. Had to remove test for now. * Fix lint. * Split across multiple files. * Changes for linting. * Run lint tool. * Potential fix for filtering issue. * Add back pinned option. * Removed extra info so tests pass again. * Test with using scorer only. If the score is 0, we can just exclude it, so seems pointless to do the regex and then that. Will need to implement the filtering some other way though. * Enable sorting with fuzzy finder. * Added back fallback comparer. * Fix lint. * Make naming consistent. * Bring in updated oni-api. * Swap to a separate filter. Bring back tests for RegEx filter. * Fix bug with filtering. * Bring over all the regex tests. Converted to check highlights and score now too. * Add score test. * Added additional test. * Added two tests for length. * Remove replace and fallback. Convert string was needed to deal with the regex, but since this is its own scorer it isn't needed. Swapping to the default fallback fixes file length sorting when scores match. * Tidy up files. * Add test for search with file extension. * Swap default. --- .../Configuration/DefaultConfiguration.ts | 2 +- browser/src/Services/QuickOpen/QuickOpen.ts | 17 +- browser/src/Services/QuickOpen/RegExFilter.ts | 4 +- .../src/Services/QuickOpen/Scorer/CharCode.ts | 422 +++++++++++ .../Services/QuickOpen/Scorer/Comparers.ts | 196 ++++++ .../QuickOpen/Scorer/OniQuickOpenScorer.ts | 78 ++ .../QuickOpen/Scorer/QuickOpenScorer.ts | 665 ++++++++++++++++++ .../Services/QuickOpen/Scorer/Utilities.ts | 41 ++ .../src/Services/QuickOpen/Scorer/filters.ts | 224 ++++++ .../src/Services/QuickOpen/Scorer/strings.ts | 71 ++ .../src/Services/QuickOpen/VSCodeFilter.ts | 83 +++ .../Services/QuickOpen/RegExFilterTests.ts | 3 + .../Services/QuickOpen/VSCodeFilterTests.ts | 287 ++++++++ package.json | 2 +- 14 files changed, 2087 insertions(+), 8 deletions(-) create mode 100644 browser/src/Services/QuickOpen/Scorer/CharCode.ts create mode 100644 browser/src/Services/QuickOpen/Scorer/Comparers.ts create mode 100644 browser/src/Services/QuickOpen/Scorer/OniQuickOpenScorer.ts create mode 100644 browser/src/Services/QuickOpen/Scorer/QuickOpenScorer.ts create mode 100644 browser/src/Services/QuickOpen/Scorer/Utilities.ts create mode 100644 browser/src/Services/QuickOpen/Scorer/filters.ts create mode 100644 browser/src/Services/QuickOpen/Scorer/strings.ts create mode 100644 browser/src/Services/QuickOpen/VSCodeFilter.ts create mode 100644 browser/test/Services/QuickOpen/VSCodeFilterTests.ts diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 42f745c7dc..0f64338aa4 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -104,7 +104,7 @@ const BaseConfiguration: IConfigurationValues = { "editor.linePadding": 2, "editor.quickOpen.execCommand": null, - "editor.quickOpen.filterStrategy": "regex", + "editor.quickOpen.filterStrategy": "vscode", "editor.split.mode": "native", diff --git a/browser/src/Services/QuickOpen/QuickOpen.ts b/browser/src/Services/QuickOpen/QuickOpen.ts index 20c2a3f386..fd5895295d 100644 --- a/browser/src/Services/QuickOpen/QuickOpen.ts +++ b/browser/src/Services/QuickOpen/QuickOpen.ts @@ -22,6 +22,7 @@ import { render as renderPinnedIcon } from "./PinnedIconView" import { QuickOpenItem, QuickOpenType } from "./QuickOpenItem" import { regexFilter } from "./RegExFilter" import * as RipGrep from "./RipGrep" +import { vsCodeFilter } from "./VSCodeFilter" import { getFileIcon } from "./../FileIcon" @@ -77,10 +78,18 @@ export class QuickOpen { const filterStrategy = configuration.getValue("editor.quickOpen.filterStrategy") - const useRegExFilter = filterStrategy === "regex" - - const filterFunction = useRegExFilter ? regexFilter : fuseFilter - this._menu.setFilterFunction(filterFunction) + switch (filterStrategy) { + case "fuse": + this._menu.setFilterFunction(fuseFilter) + break + case "regex": + this._menu.setFilterFunction(regexFilter) + break + case "vscode": + default: + this._menu.setFilterFunction(vsCodeFilter) + break + } // If in exec directory or home, show bookmarks to change cwd to if (this._isInstallDirectoryOrHome()) { diff --git a/browser/src/Services/QuickOpen/RegExFilter.ts b/browser/src/Services/QuickOpen/RegExFilter.ts index 3fa7f0c475..d11a5d1907 100644 --- a/browser/src/Services/QuickOpen/RegExFilter.ts +++ b/browser/src/Services/QuickOpen/RegExFilter.ts @@ -1,7 +1,7 @@ /** - * MenuFilter.ts + * RegExFilter.ts * - * Implements filtering logic for the menu + * Implements RegEx filtering logic for the menu */ import * as sortBy from "lodash/sortBy" diff --git a/browser/src/Services/QuickOpen/Scorer/CharCode.ts b/browser/src/Services/QuickOpen/Scorer/CharCode.ts new file mode 100644 index 0000000000..22080f8c8d --- /dev/null +++ b/browser/src/Services/QuickOpen/Scorer/CharCode.ts @@ -0,0 +1,422 @@ +/* tslint:disable */ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +"use strict" + +// Names from https://blog.codinghorror.com/ascii-pronunciation-rules-for-programmers/ + +/** + * An inlined enum containing useful character codes (to be used with String.charCodeAt). + * Please leave the const keyword such that it gets inlined when compiled to JavaScript! + */ +export const enum CharCode { + Null = 0, + /** + * The `\t` character. + */ + Tab = 9, + /** + * The `\n` character. + */ + LineFeed = 10, + /** + * The `\r` character. + */ + CarriageReturn = 13, + Space = 32, + /** + * The `!` character. + */ + ExclamationMark = 33, + /** + * The `"` character. + */ + DoubleQuote = 34, + /** + * The `#` character. + */ + Hash = 35, + /** + * The `$` character. + */ + DollarSign = 36, + /** + * The `%` character. + */ + PercentSign = 37, + /** + * The `&` character. + */ + Ampersand = 38, + /** + * The `'` character. + */ + SingleQuote = 39, + /** + * The `(` character. + */ + OpenParen = 40, + /** + * The `)` character. + */ + CloseParen = 41, + /** + * The `*` character. + */ + Asterisk = 42, + /** + * The `+` character. + */ + Plus = 43, + /** + * The `,` character. + */ + Comma = 44, + /** + * The `-` character. + */ + Dash = 45, + /** + * The `.` character. + */ + Period = 46, + /** + * The `/` character. + */ + Slash = 47, + + Digit0 = 48, + Digit1 = 49, + Digit2 = 50, + Digit3 = 51, + Digit4 = 52, + Digit5 = 53, + Digit6 = 54, + Digit7 = 55, + Digit8 = 56, + Digit9 = 57, + + /** + * The `:` character. + */ + Colon = 58, + /** + * The `;` character. + */ + Semicolon = 59, + /** + * The `<` character. + */ + LessThan = 60, + /** + * The `=` character. + */ + Equals = 61, + /** + * The `>` character. + */ + GreaterThan = 62, + /** + * The `?` character. + */ + QuestionMark = 63, + /** + * The `@` character. + */ + AtSign = 64, + + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + + /** + * The `[` character. + */ + OpenSquareBracket = 91, + /** + * The `\` character. + */ + Backslash = 92, + /** + * The `]` character. + */ + CloseSquareBracket = 93, + /** + * The `^` character. + */ + Caret = 94, + /** + * The `_` character. + */ + Underline = 95, + /** + * The ``(`)`` character. + */ + BackTick = 96, + + a = 97, + b = 98, + c = 99, + d = 100, + e = 101, + f = 102, + g = 103, + h = 104, + i = 105, + j = 106, + k = 107, + l = 108, + m = 109, + n = 110, + o = 111, + p = 112, + q = 113, + r = 114, + s = 115, + t = 116, + u = 117, + v = 118, + w = 119, + x = 120, + y = 121, + z = 122, + + /** + * The `{` character. + */ + OpenCurlyBrace = 123, + /** + * The `|` character. + */ + Pipe = 124, + /** + * The `}` character. + */ + CloseCurlyBrace = 125, + /** + * The `~` character. + */ + Tilde = 126, + + U_Combining_Grave_Accent = 0x0300, // U+0300 Combining Grave Accent + U_Combining_Acute_Accent = 0x0301, // U+0301 Combining Acute Accent + U_Combining_Circumflex_Accent = 0x0302, // U+0302 Combining Circumflex Accent + U_Combining_Tilde = 0x0303, // U+0303 Combining Tilde + U_Combining_Macron = 0x0304, // U+0304 Combining Macron + U_Combining_Overline = 0x0305, // U+0305 Combining Overline + U_Combining_Breve = 0x0306, // U+0306 Combining Breve + U_Combining_Dot_Above = 0x0307, // U+0307 Combining Dot Above + U_Combining_Diaeresis = 0x0308, // U+0308 Combining Diaeresis + U_Combining_Hook_Above = 0x0309, // U+0309 Combining Hook Above + U_Combining_Ring_Above = 0x030a, // U+030A Combining Ring Above + U_Combining_Double_Acute_Accent = 0x030b, // U+030B Combining Double Acute Accent + U_Combining_Caron = 0x030c, // U+030C Combining Caron + U_Combining_Vertical_Line_Above = 0x030d, // U+030D Combining Vertical Line Above + U_Combining_Double_Vertical_Line_Above = 0x030e, // U+030E Combining Double Vertical Line Above + U_Combining_Double_Grave_Accent = 0x030f, // U+030F Combining Double Grave Accent + U_Combining_Candrabindu = 0x0310, // U+0310 Combining Candrabindu + U_Combining_Inverted_Breve = 0x0311, // U+0311 Combining Inverted Breve + U_Combining_Turned_Comma_Above = 0x0312, // U+0312 Combining Turned Comma Above + U_Combining_Comma_Above = 0x0313, // U+0313 Combining Comma Above + U_Combining_Reversed_Comma_Above = 0x0314, // U+0314 Combining Reversed Comma Above + U_Combining_Comma_Above_Right = 0x0315, // U+0315 Combining Comma Above Right + U_Combining_Grave_Accent_Below = 0x0316, // U+0316 Combining Grave Accent Below + U_Combining_Acute_Accent_Below = 0x0317, // U+0317 Combining Acute Accent Below + U_Combining_Left_Tack_Below = 0x0318, // U+0318 Combining Left Tack Below + U_Combining_Right_Tack_Below = 0x0319, // U+0319 Combining Right Tack Below + U_Combining_Left_Angle_Above = 0x031a, // U+031A Combining Left Angle Above + U_Combining_Horn = 0x031b, // U+031B Combining Horn + U_Combining_Left_Half_Ring_Below = 0x031c, // U+031C Combining Left Half Ring Below + U_Combining_Up_Tack_Below = 0x031d, // U+031D Combining Up Tack Below + U_Combining_Down_Tack_Below = 0x031e, // U+031E Combining Down Tack Below + U_Combining_Plus_Sign_Below = 0x031f, // U+031F Combining Plus Sign Below + U_Combining_Minus_Sign_Below = 0x0320, // U+0320 Combining Minus Sign Below + U_Combining_Palatalized_Hook_Below = 0x0321, // U+0321 Combining Palatalized Hook Below + U_Combining_Retroflex_Hook_Below = 0x0322, // U+0322 Combining Retroflex Hook Below + U_Combining_Dot_Below = 0x0323, // U+0323 Combining Dot Below + U_Combining_Diaeresis_Below = 0x0324, // U+0324 Combining Diaeresis Below + U_Combining_Ring_Below = 0x0325, // U+0325 Combining Ring Below + U_Combining_Comma_Below = 0x0326, // U+0326 Combining Comma Below + U_Combining_Cedilla = 0x0327, // U+0327 Combining Cedilla + U_Combining_Ogonek = 0x0328, // U+0328 Combining Ogonek + U_Combining_Vertical_Line_Below = 0x0329, // U+0329 Combining Vertical Line Below + U_Combining_Bridge_Below = 0x032a, // U+032A Combining Bridge Below + U_Combining_Inverted_Double_Arch_Below = 0x032b, // U+032B Combining Inverted Double Arch Below + U_Combining_Caron_Below = 0x032c, // U+032C Combining Caron Below + U_Combining_Circumflex_Accent_Below = 0x032d, // U+032D Combining Circumflex Accent Below + U_Combining_Breve_Below = 0x032e, // U+032E Combining Breve Below + U_Combining_Inverted_Breve_Below = 0x032f, // U+032F Combining Inverted Breve Below + U_Combining_Tilde_Below = 0x0330, // U+0330 Combining Tilde Below + U_Combining_Macron_Below = 0x0331, // U+0331 Combining Macron Below + U_Combining_Low_Line = 0x0332, // U+0332 Combining Low Line + U_Combining_Double_Low_Line = 0x0333, // U+0333 Combining Double Low Line + U_Combining_Tilde_Overlay = 0x0334, // U+0334 Combining Tilde Overlay + U_Combining_Short_Stroke_Overlay = 0x0335, // U+0335 Combining Short Stroke Overlay + U_Combining_Long_Stroke_Overlay = 0x0336, // U+0336 Combining Long Stroke Overlay + U_Combining_Short_Solidus_Overlay = 0x0337, // U+0337 Combining Short Solidus Overlay + U_Combining_Long_Solidus_Overlay = 0x0338, // U+0338 Combining Long Solidus Overlay + U_Combining_Right_Half_Ring_Below = 0x0339, // U+0339 Combining Right Half Ring Below + U_Combining_Inverted_Bridge_Below = 0x033a, // U+033A Combining Inverted Bridge Below + U_Combining_Square_Below = 0x033b, // U+033B Combining Square Below + U_Combining_Seagull_Below = 0x033c, // U+033C Combining Seagull Below + U_Combining_X_Above = 0x033d, // U+033D Combining X Above + U_Combining_Vertical_Tilde = 0x033e, // U+033E Combining Vertical Tilde + U_Combining_Double_Overline = 0x033f, // U+033F Combining Double Overline + U_Combining_Grave_Tone_Mark = 0x0340, // U+0340 Combining Grave Tone Mark + U_Combining_Acute_Tone_Mark = 0x0341, // U+0341 Combining Acute Tone Mark + U_Combining_Greek_Perispomeni = 0x0342, // U+0342 Combining Greek Perispomeni + U_Combining_Greek_Koronis = 0x0343, // U+0343 Combining Greek Koronis + U_Combining_Greek_Dialytika_Tonos = 0x0344, // U+0344 Combining Greek Dialytika Tonos + U_Combining_Greek_Ypogegrammeni = 0x0345, // U+0345 Combining Greek Ypogegrammeni + U_Combining_Bridge_Above = 0x0346, // U+0346 Combining Bridge Above + U_Combining_Equals_Sign_Below = 0x0347, // U+0347 Combining Equals Sign Below + U_Combining_Double_Vertical_Line_Below = 0x0348, // U+0348 Combining Double Vertical Line Below + U_Combining_Left_Angle_Below = 0x0349, // U+0349 Combining Left Angle Below + U_Combining_Not_Tilde_Above = 0x034a, // U+034A Combining Not Tilde Above + U_Combining_Homothetic_Above = 0x034b, // U+034B Combining Homothetic Above + U_Combining_Almost_Equal_To_Above = 0x034c, // U+034C Combining Almost Equal To Above + U_Combining_Left_Right_Arrow_Below = 0x034d, // U+034D Combining Left Right Arrow Below + U_Combining_Upwards_Arrow_Below = 0x034e, // U+034E Combining Upwards Arrow Below + U_Combining_Grapheme_Joiner = 0x034f, // U+034F Combining Grapheme Joiner + U_Combining_Right_Arrowhead_Above = 0x0350, // U+0350 Combining Right Arrowhead Above + U_Combining_Left_Half_Ring_Above = 0x0351, // U+0351 Combining Left Half Ring Above + U_Combining_Fermata = 0x0352, // U+0352 Combining Fermata + U_Combining_X_Below = 0x0353, // U+0353 Combining X Below + U_Combining_Left_Arrowhead_Below = 0x0354, // U+0354 Combining Left Arrowhead Below + U_Combining_Right_Arrowhead_Below = 0x0355, // U+0355 Combining Right Arrowhead Below + U_Combining_Right_Arrowhead_And_Up_Arrowhead_Below = 0x0356, // U+0356 Combining Right Arrowhead And Up Arrowhead Below + U_Combining_Right_Half_Ring_Above = 0x0357, // U+0357 Combining Right Half Ring Above + U_Combining_Dot_Above_Right = 0x0358, // U+0358 Combining Dot Above Right + U_Combining_Asterisk_Below = 0x0359, // U+0359 Combining Asterisk Below + U_Combining_Double_Ring_Below = 0x035a, // U+035A Combining Double Ring Below + U_Combining_Zigzag_Above = 0x035b, // U+035B Combining Zigzag Above + U_Combining_Double_Breve_Below = 0x035c, // U+035C Combining Double Breve Below + U_Combining_Double_Breve = 0x035d, // U+035D Combining Double Breve + U_Combining_Double_Macron = 0x035e, // U+035E Combining Double Macron + U_Combining_Double_Macron_Below = 0x035f, // U+035F Combining Double Macron Below + U_Combining_Double_Tilde = 0x0360, // U+0360 Combining Double Tilde + U_Combining_Double_Inverted_Breve = 0x0361, // U+0361 Combining Double Inverted Breve + U_Combining_Double_Rightwards_Arrow_Below = 0x0362, // U+0362 Combining Double Rightwards Arrow Below + U_Combining_Latin_Small_Letter_A = 0x0363, // U+0363 Combining Latin Small Letter A + U_Combining_Latin_Small_Letter_E = 0x0364, // U+0364 Combining Latin Small Letter E + U_Combining_Latin_Small_Letter_I = 0x0365, // U+0365 Combining Latin Small Letter I + U_Combining_Latin_Small_Letter_O = 0x0366, // U+0366 Combining Latin Small Letter O + U_Combining_Latin_Small_Letter_U = 0x0367, // U+0367 Combining Latin Small Letter U + U_Combining_Latin_Small_Letter_C = 0x0368, // U+0368 Combining Latin Small Letter C + U_Combining_Latin_Small_Letter_D = 0x0369, // U+0369 Combining Latin Small Letter D + U_Combining_Latin_Small_Letter_H = 0x036a, // U+036A Combining Latin Small Letter H + U_Combining_Latin_Small_Letter_M = 0x036b, // U+036B Combining Latin Small Letter M + U_Combining_Latin_Small_Letter_R = 0x036c, // U+036C Combining Latin Small Letter R + U_Combining_Latin_Small_Letter_T = 0x036d, // U+036D Combining Latin Small Letter T + U_Combining_Latin_Small_Letter_V = 0x036e, // U+036E Combining Latin Small Letter V + U_Combining_Latin_Small_Letter_X = 0x036f, // U+036F Combining Latin Small Letter X + + /** + * Unicode Character 'LINE SEPARATOR' (U+2028) + * http://www.fileformat.info/info/unicode/char/2028/index.htm + */ + LINE_SEPARATOR_2028 = 8232, + + // http://www.fileformat.info/info/unicode/category/Sk/list.htm + U_CIRCUMFLEX = 0x005e, // U+005E CIRCUMFLEX + U_GRAVE_ACCENT = 0x0060, // U+0060 GRAVE ACCENT + U_DIAERESIS = 0x00a8, // U+00A8 DIAERESIS + U_MACRON = 0x00af, // U+00AF MACRON + U_ACUTE_ACCENT = 0x00b4, // U+00B4 ACUTE ACCENT + U_CEDILLA = 0x00b8, // U+00B8 CEDILLA + U_MODIFIER_LETTER_LEFT_ARROWHEAD = 0x02c2, // U+02C2 MODIFIER LETTER LEFT ARROWHEAD + U_MODIFIER_LETTER_RIGHT_ARROWHEAD = 0x02c3, // U+02C3 MODIFIER LETTER RIGHT ARROWHEAD + U_MODIFIER_LETTER_UP_ARROWHEAD = 0x02c4, // U+02C4 MODIFIER LETTER UP ARROWHEAD + U_MODIFIER_LETTER_DOWN_ARROWHEAD = 0x02c5, // U+02C5 MODIFIER LETTER DOWN ARROWHEAD + U_MODIFIER_LETTER_CENTRED_RIGHT_HALF_RING = 0x02d2, // U+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING + U_MODIFIER_LETTER_CENTRED_LEFT_HALF_RING = 0x02d3, // U+02D3 MODIFIER LETTER CENTRED LEFT HALF RING + U_MODIFIER_LETTER_UP_TACK = 0x02d4, // U+02D4 MODIFIER LETTER UP TACK + U_MODIFIER_LETTER_DOWN_TACK = 0x02d5, // U+02D5 MODIFIER LETTER DOWN TACK + U_MODIFIER_LETTER_PLUS_SIGN = 0x02d6, // U+02D6 MODIFIER LETTER PLUS SIGN + U_MODIFIER_LETTER_MINUS_SIGN = 0x02d7, // U+02D7 MODIFIER LETTER MINUS SIGN + U_BREVE = 0x02d8, // U+02D8 BREVE + U_DOT_ABOVE = 0x02d9, // U+02D9 DOT ABOVE + U_RING_ABOVE = 0x02da, // U+02DA RING ABOVE + U_OGONEK = 0x02db, // U+02DB OGONEK + U_SMALL_TILDE = 0x02dc, // U+02DC SMALL TILDE + U_DOUBLE_ACUTE_ACCENT = 0x02dd, // U+02DD DOUBLE ACUTE ACCENT + U_MODIFIER_LETTER_RHOTIC_HOOK = 0x02de, // U+02DE MODIFIER LETTER RHOTIC HOOK + U_MODIFIER_LETTER_CROSS_ACCENT = 0x02df, // U+02DF MODIFIER LETTER CROSS ACCENT + U_MODIFIER_LETTER_EXTRA_HIGH_TONE_BAR = 0x02e5, // U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR + U_MODIFIER_LETTER_HIGH_TONE_BAR = 0x02e6, // U+02E6 MODIFIER LETTER HIGH TONE BAR + U_MODIFIER_LETTER_MID_TONE_BAR = 0x02e7, // U+02E7 MODIFIER LETTER MID TONE BAR + U_MODIFIER_LETTER_LOW_TONE_BAR = 0x02e8, // U+02E8 MODIFIER LETTER LOW TONE BAR + U_MODIFIER_LETTER_EXTRA_LOW_TONE_BAR = 0x02e9, // U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR + U_MODIFIER_LETTER_YIN_DEPARTING_TONE_MARK = 0x02ea, // U+02EA MODIFIER LETTER YIN DEPARTING TONE MARK + U_MODIFIER_LETTER_YANG_DEPARTING_TONE_MARK = 0x02eb, // U+02EB MODIFIER LETTER YANG DEPARTING TONE MARK + U_MODIFIER_LETTER_UNASPIRATED = 0x02ed, // U+02ED MODIFIER LETTER UNASPIRATED + U_MODIFIER_LETTER_LOW_DOWN_ARROWHEAD = 0x02ef, // U+02EF MODIFIER LETTER LOW DOWN ARROWHEAD + U_MODIFIER_LETTER_LOW_UP_ARROWHEAD = 0x02f0, // U+02F0 MODIFIER LETTER LOW UP ARROWHEAD + U_MODIFIER_LETTER_LOW_LEFT_ARROWHEAD = 0x02f1, // U+02F1 MODIFIER LETTER LOW LEFT ARROWHEAD + U_MODIFIER_LETTER_LOW_RIGHT_ARROWHEAD = 0x02f2, // U+02F2 MODIFIER LETTER LOW RIGHT ARROWHEAD + U_MODIFIER_LETTER_LOW_RING = 0x02f3, // U+02F3 MODIFIER LETTER LOW RING + U_MODIFIER_LETTER_MIDDLE_GRAVE_ACCENT = 0x02f4, // U+02F4 MODIFIER LETTER MIDDLE GRAVE ACCENT + U_MODIFIER_LETTER_MIDDLE_DOUBLE_GRAVE_ACCENT = 0x02f5, // U+02F5 MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT + U_MODIFIER_LETTER_MIDDLE_DOUBLE_ACUTE_ACCENT = 0x02f6, // U+02F6 MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT + U_MODIFIER_LETTER_LOW_TILDE = 0x02f7, // U+02F7 MODIFIER LETTER LOW TILDE + U_MODIFIER_LETTER_RAISED_COLON = 0x02f8, // U+02F8 MODIFIER LETTER RAISED COLON + U_MODIFIER_LETTER_BEGIN_HIGH_TONE = 0x02f9, // U+02F9 MODIFIER LETTER BEGIN HIGH TONE + U_MODIFIER_LETTER_END_HIGH_TONE = 0x02fa, // U+02FA MODIFIER LETTER END HIGH TONE + U_MODIFIER_LETTER_BEGIN_LOW_TONE = 0x02fb, // U+02FB MODIFIER LETTER BEGIN LOW TONE + U_MODIFIER_LETTER_END_LOW_TONE = 0x02fc, // U+02FC MODIFIER LETTER END LOW TONE + U_MODIFIER_LETTER_SHELF = 0x02fd, // U+02FD MODIFIER LETTER SHELF + U_MODIFIER_LETTER_OPEN_SHELF = 0x02fe, // U+02FE MODIFIER LETTER OPEN SHELF + U_MODIFIER_LETTER_LOW_LEFT_ARROW = 0x02ff, // U+02FF MODIFIER LETTER LOW LEFT ARROW + U_GREEK_LOWER_NUMERAL_SIGN = 0x0375, // U+0375 GREEK LOWER NUMERAL SIGN + U_GREEK_TONOS = 0x0384, // U+0384 GREEK TONOS + U_GREEK_DIALYTIKA_TONOS = 0x0385, // U+0385 GREEK DIALYTIKA TONOS + U_GREEK_KORONIS = 0x1fbd, // U+1FBD GREEK KORONIS + U_GREEK_PSILI = 0x1fbf, // U+1FBF GREEK PSILI + U_GREEK_PERISPOMENI = 0x1fc0, // U+1FC0 GREEK PERISPOMENI + U_GREEK_DIALYTIKA_AND_PERISPOMENI = 0x1fc1, // U+1FC1 GREEK DIALYTIKA AND PERISPOMENI + U_GREEK_PSILI_AND_VARIA = 0x1fcd, // U+1FCD GREEK PSILI AND VARIA + U_GREEK_PSILI_AND_OXIA = 0x1fce, // U+1FCE GREEK PSILI AND OXIA + U_GREEK_PSILI_AND_PERISPOMENI = 0x1fcf, // U+1FCF GREEK PSILI AND PERISPOMENI + U_GREEK_DASIA_AND_VARIA = 0x1fdd, // U+1FDD GREEK DASIA AND VARIA + U_GREEK_DASIA_AND_OXIA = 0x1fde, // U+1FDE GREEK DASIA AND OXIA + U_GREEK_DASIA_AND_PERISPOMENI = 0x1fdf, // U+1FDF GREEK DASIA AND PERISPOMENI + U_GREEK_DIALYTIKA_AND_VARIA = 0x1fed, // U+1FED GREEK DIALYTIKA AND VARIA + U_GREEK_DIALYTIKA_AND_OXIA = 0x1fee, // U+1FEE GREEK DIALYTIKA AND OXIA + U_GREEK_VARIA = 0x1fef, // U+1FEF GREEK VARIA + U_GREEK_OXIA = 0x1ffd, // U+1FFD GREEK OXIA + U_GREEK_DASIA = 0x1ffe, // U+1FFE GREEK DASIA + + U_OVERLINE = 0x203e, // Unicode Character 'OVERLINE' + + /** + * UTF-8 BOM + * Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF) + * http://www.fileformat.info/info/unicode/char/feff/index.htm + */ + UTF8_BOM = 65279, +} diff --git a/browser/src/Services/QuickOpen/Scorer/Comparers.ts b/browser/src/Services/QuickOpen/Scorer/Comparers.ts new file mode 100644 index 0000000000..39ce1264e7 --- /dev/null +++ b/browser/src/Services/QuickOpen/Scorer/Comparers.ts @@ -0,0 +1,196 @@ +/* tslint:disable */ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +"use strict" + +import { nativeSep } from "./Utilities" + +let intlFileNameCollator: Intl.Collator +let intlFileNameCollatorIsNumeric: boolean + +export function setFileNameComparer(collator: Intl.Collator): void { + intlFileNameCollator = collator + intlFileNameCollatorIsNumeric = collator.resolvedOptions().numeric +} + +export function compareFileNames(one: string, other: string, caseSensitive = false): number { + if (intlFileNameCollator) { + const a = one || "" + const b = other || "" + const result = intlFileNameCollator.compare(a, b) + + // Using the numeric option in the collator will + // make compare(`foo1`, `foo01`) === 0. We must disambiguate. + if (intlFileNameCollatorIsNumeric && result === 0 && a !== b) { + return a < b ? -1 : 1 + } + + return result + } + + return noIntlCompareFileNames(one, other, caseSensitive) +} + +const FileNameMatch = /^(.*?)(\.([^.]*))?$/ + +export function noIntlCompareFileNames(one: string, other: string, caseSensitive = false): number { + if (!caseSensitive) { + one = one && one.toLowerCase() + other = other && other.toLowerCase() + } + + const [oneName, oneExtension] = extractNameAndExtension(one) + const [otherName, otherExtension] = extractNameAndExtension(other) + + if (oneName !== otherName) { + return oneName < otherName ? -1 : 1 + } + + if (oneExtension === otherExtension) { + return 0 + } + + return oneExtension < otherExtension ? -1 : 1 +} + +export function compareFileExtensions(one: string, other: string): number { + if (intlFileNameCollator) { + const [oneName, oneExtension] = extractNameAndExtension(one) + const [otherName, otherExtension] = extractNameAndExtension(other) + + let result = intlFileNameCollator.compare(oneExtension, otherExtension) + + if (result === 0) { + // Using the numeric option in the collator will + // make compare(`foo1`, `foo01`) === 0. We must disambiguate. + if (intlFileNameCollatorIsNumeric && oneExtension !== otherExtension) { + return oneExtension < otherExtension ? -1 : 1 + } + + // Extensions are equal, compare filenames + result = intlFileNameCollator.compare(oneName, otherName) + + if (intlFileNameCollatorIsNumeric && result === 0 && oneName !== otherName) { + return oneName < otherName ? -1 : 1 + } + } + + return result + } + + return noIntlCompareFileExtensions(one, other) +} + +function noIntlCompareFileExtensions(one: string, other: string): number { + const [oneName, oneExtension] = extractNameAndExtension(one && one.toLowerCase()) + const [otherName, otherExtension] = extractNameAndExtension(other && other.toLowerCase()) + + if (oneExtension !== otherExtension) { + return oneExtension < otherExtension ? -1 : 1 + } + + if (oneName === otherName) { + return 0 + } + + return oneName < otherName ? -1 : 1 +} + +function extractNameAndExtension(str?: string): [string, string] { + const match = str ? FileNameMatch.exec(str) : ([] as RegExpExecArray) + + return [(match && match[1]) || "", (match && match[3]) || ""] +} + +function comparePathComponents(one: string, other: string, caseSensitive = false): number { + if (!caseSensitive) { + one = one && one.toLowerCase() + other = other && other.toLowerCase() + } + + if (one === other) { + return 0 + } + + return one < other ? -1 : 1 +} + +export function comparePaths(one: string, other: string, caseSensitive = false): number { + const oneParts = one.split(nativeSep) + const otherParts = other.split(nativeSep) + + const lastOne = oneParts.length - 1 + const lastOther = otherParts.length - 1 + let endOne: boolean, endOther: boolean + + for (let i = 0; ; i++) { + endOne = lastOne === i + endOther = lastOther === i + + if (endOne && endOther) { + return compareFileNames(oneParts[i], otherParts[i], caseSensitive) + } else if (endOne) { + return -1 + } else if (endOther) { + return 1 + } + + const result = comparePathComponents(oneParts[i], otherParts[i], caseSensitive) + + if (result !== 0) { + return result + } + } +} + +export function compareAnything(one: string, other: string, lookFor: string): number { + let elementAName = one.toLowerCase() + let elementBName = other.toLowerCase() + + // Sort prefix matches over non prefix matches + const prefixCompare = compareByPrefix(one, other, lookFor) + if (prefixCompare) { + return prefixCompare + } + + // Sort suffix matches over non suffix matches + let elementASuffixMatch = elementAName.endsWith(lookFor) + let elementBSuffixMatch = elementBName.endsWith(lookFor) + if (elementASuffixMatch !== elementBSuffixMatch) { + return elementASuffixMatch ? -1 : 1 + } + + // Understand file names + let r = compareFileNames(elementAName, elementBName) + if (r !== 0) { + return r + } + + // Compare by name + return elementAName.localeCompare(elementBName) +} + +export function compareByPrefix(one: string, other: string, lookFor: string): number { + let elementAName = one.toLowerCase() + let elementBName = other.toLowerCase() + + // Sort prefix matches over non prefix matches + let elementAPrefixMatch = elementAName.startsWith(lookFor) + let elementBPrefixMatch = elementBName.startsWith(lookFor) + if (elementAPrefixMatch !== elementBPrefixMatch) { + return elementAPrefixMatch ? -1 : 1 + } else if (elementAPrefixMatch && elementBPrefixMatch) { + // Same prefix: Sort shorter matches to the top to have those on top that match more precisely + if (elementAName.length < elementBName.length) { + return -1 + } + + if (elementAName.length > elementBName.length) { + return 1 + } + } + + return 0 +} diff --git a/browser/src/Services/QuickOpen/Scorer/OniQuickOpenScorer.ts b/browser/src/Services/QuickOpen/Scorer/OniQuickOpenScorer.ts new file mode 100644 index 0000000000..39a162c138 --- /dev/null +++ b/browser/src/Services/QuickOpen/Scorer/OniQuickOpenScorer.ts @@ -0,0 +1,78 @@ +import { IMatch } from "./filters" +import { + compareItemsByScore, + IItemAccessor, + IItemScore, + prepareQuery, + scoreItem, +} from "./QuickOpenScorer" +import { nativeSep } from "./Utilities" + +export const NO_ITEM_SCORE: IItemScore = Object.freeze({ score: 0 }) + +class OniAccessor implements IItemAccessor { + public getItemLabel(result: any): string { + return result.label ? result.label : "" + } + + public getItemDescription(result: any): string { + return result.detail ? result.detail : "" + } + + public getItemPath(result: any): string { + return result.detail + nativeSep + result.label + } +} + +export function scoreItemOni(resultObject: any, searchString: string, fuzzy: boolean): IItemScore { + if (!searchString) { + return NO_ITEM_SCORE + } + + const query = prepareQuery(searchString) + + if (!resultObject || !query.value) { + return NO_ITEM_SCORE + } + + const accessor = new OniAccessor() + + return scoreItem(resultObject, query, fuzzy, accessor) +} + +export function compareItemsByScoreOni( + resultObjectA: any, + resultObjectB: any, + searchString: string, + fuzzy: boolean, +): number { + if (!searchString) { + return 0 + } + + const query = prepareQuery(searchString) + + if (!resultObjectA || !resultObjectB || !query.value) { + return 0 + } + + const accessor = new OniAccessor() + + return compareItemsByScore(resultObjectA, resultObjectB, query, fuzzy, accessor) +} + +export const getHighlightsFromResult = (result: IMatch[]): number[] => { + if (!result) { + return [] + } + + const highlights: number[] = [] + + result.forEach(r => { + for (let i = r.start; i < r.end; i++) { + highlights.push(i) + } + }) + + return highlights +} diff --git a/browser/src/Services/QuickOpen/Scorer/QuickOpenScorer.ts b/browser/src/Services/QuickOpen/Scorer/QuickOpenScorer.ts new file mode 100644 index 0000000000..965f5df118 --- /dev/null +++ b/browser/src/Services/QuickOpen/Scorer/QuickOpenScorer.ts @@ -0,0 +1,665 @@ +/* tslint:disable */ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +"use strict" + +import { CharCode } from "./CharCode" +import { compareAnything } from "./Comparers" +import { createMatches, IMatch, matchesCamelCase, matchesPrefix } from "./filters" +import { equalsIgnoreCase } from "./strings" +import { isLinux, isWindows, stripWildcards, nativeSep, isUpper } from "./Utilities" + +export type Score = [number /* score */, number[] /* match positions */] +export type ScorerCache = { [key: string]: IItemScore } + +const NO_MATCH = 0 +const NO_SCORE: Score = [NO_MATCH, []] + +// const DEBUG = false; +// const DEBUG_MATRIX = false; + +export function score(target: string, query: string, queryLower: string, fuzzy: boolean): Score { + if (!target || !query) { + return NO_SCORE // return early if target or query are undefined + } + + const targetLength = target.length + const queryLength = query.length + + if (targetLength < queryLength) { + return NO_SCORE // impossible for query to be contained in target + } + + // if (DEBUG) { + // console.group(`Target: ${target}, Query: ${query}`); + // } + + const targetLower = target.toLowerCase() + + // When not searching fuzzy, we require the query to be contained fully + // in the target string contiguously. + if (!fuzzy) { + const indexOfQueryInTarget = targetLower.indexOf(queryLower) + if (indexOfQueryInTarget === -1) { + // if (DEBUG) { + // console.log(`Characters not matching consecutively ${queryLower} within ${targetLower}`); + // } + + return NO_SCORE + } + } + + const res = doScore(query, queryLower, queryLength, target, targetLower, targetLength) + + // if (DEBUG) { + // console.log(`%cFinal Score: ${res[0]}`, 'font-weight: bold'); + // console.groupEnd(); + // } + + return res +} + +function doScore( + query: string, + queryLower: string, + queryLength: number, + target: string, + targetLower: string, + targetLength: number, +): [number, number[]] { + const scores = [] + const matches = [] + + // + // Build Scorer Matrix: + // + // The matrix is composed of query q and target t. For each index we score + // q[i] with t[i] and compare that with the previous score. If the score is + // equal or larger, we keep the match. In addition to the score, we also keep + // the length of the consecutive matches to use as boost for the score. + // + // t a r g e t + // q + // u + // e + // r + // y + // + for (let queryIndex = 0; queryIndex < queryLength; queryIndex++) { + for (let targetIndex = 0; targetIndex < targetLength; targetIndex++) { + const currentIndex = queryIndex * targetLength + targetIndex + const leftIndex = currentIndex - 1 + const diagIndex = (queryIndex - 1) * targetLength + targetIndex - 1 + + const leftScore: number = targetIndex > 0 ? scores[leftIndex] : 0 + const diagScore: number = queryIndex > 0 && targetIndex > 0 ? scores[diagIndex] : 0 + + const matchesSequenceLength: number = + queryIndex > 0 && targetIndex > 0 ? matches[diagIndex] : 0 + + // If we are not matching on the first query character any more, we only produce a + // score if we had a score previously for the last query index (by looking at the diagScore). + // This makes sure that the query always matches in sequence on the target. For example + // given a target of "ede" and a query of "de", we would otherwise produce a wrong high score + // for query[1] ("e") matching on target[0] ("e") because of the "beginning of word" boost. + let score: number + if (!diagScore && queryIndex > 0) { + score = 0 + } else { + score = computeCharScore( + query, + queryLower, + queryIndex, + target, + targetLower, + targetIndex, + matchesSequenceLength, + ) + } + + // We have a score and its equal or larger than the left score + // Match: sequence continues growing from previous diag value + // Score: increases by diag score value + if (score && diagScore + score >= leftScore) { + matches[currentIndex] = matchesSequenceLength + 1 + scores[currentIndex] = diagScore + score + } else { + // We either have no score or the score is lower than the left score + // Match: reset to 0 + // Score: pick up from left hand side + matches[currentIndex] = NO_MATCH + scores[currentIndex] = leftScore + } + } + } + + // Restore Positions (starting from bottom right of matrix) + const positions = [] + let queryIndex = queryLength - 1 + let targetIndex = targetLength - 1 + while (queryIndex >= 0 && targetIndex >= 0) { + const currentIndex = queryIndex * targetLength + targetIndex + const match = matches[currentIndex] + if (match === NO_MATCH) { + targetIndex-- // go left + } else { + positions.push(targetIndex) + + // go up and left + queryIndex-- + targetIndex-- + } + } + + // Print matrix + // if (DEBUG_MATRIX) { + // printMatrix(query, target, matches, scores); + // } + + return [scores[queryLength * targetLength - 1], positions.reverse()] +} + +function computeCharScore( + query: string, + queryLower: string, + queryIndex: number, + target: string, + targetLower: string, + targetIndex: number, + matchesSequenceLength: number, +): number { + let score = 0 + + if (queryLower[queryIndex] !== targetLower[targetIndex]) { + return score // no match of characters + } + + // Character match bonus + score += 1 + + // if (DEBUG) { + // console.groupCollapsed(`%cCharacter match bonus: +1 (char: ${queryLower[queryIndex]} at index ${targetIndex}, total score: ${score})`, 'font-weight: normal'); + // } + + // Consecutive match bonus + if (matchesSequenceLength > 0) { + score += matchesSequenceLength * 5 + + // if (DEBUG) { + // console.log('Consecutive match bonus: ' + (matchesSequenceLength * 5)); + // } + } + + // Same case bonus + if (query[queryIndex] === target[targetIndex]) { + score += 1 + + // if (DEBUG) { + // console.log('Same case bonus: +1'); + // } + } + + // Start of word bonus + if (targetIndex === 0) { + score += 8 + + // if (DEBUG) { + // console.log('Start of word bonus: +8'); + // } + } else { + // After separator bonus + const separatorBonus = scoreSeparatorAtPos(target.charCodeAt(targetIndex - 1)) + if (separatorBonus) { + score += separatorBonus + + // if (DEBUG) { + // console.log('After separtor bonus: +4'); + // } + } else if (isUpper(target.charCodeAt(targetIndex))) { + // Inside word upper case bonus (camel case) + score += 1 + + // if (DEBUG) { + // console.log('Inside word upper case bonus: +1'); + // } + } + } + + // if (DEBUG) { + // console.groupEnd(); + // } + + return score +} + +function scoreSeparatorAtPos(charCode: number): number { + switch (charCode) { + case CharCode.Slash: + case CharCode.Backslash: + return 5 // prefer path separators... + case CharCode.Underline: + case CharCode.Dash: + case CharCode.Period: + case CharCode.Space: + case CharCode.SingleQuote: + case CharCode.DoubleQuote: + case CharCode.Colon: + return 4 // ...over other separators + default: + return 0 + } +} + +// function printMatrix(query: string, target: string, matches: number[], scores: number[]): void { +// console.log('\t' + target.split('').join('\t')); +// for (let queryIndex = 0; queryIndex < query.length; queryIndex++) { +// let line = query[queryIndex] + '\t'; +// for (let targetIndex = 0; targetIndex < target.length; targetIndex++) { +// const currentIndex = queryIndex * target.length + targetIndex; +// line = line + 'M' + matches[currentIndex] + '/' + 'S' + scores[currentIndex] + '\t'; +// } + +// console.log(line); +// } +// } + +/** + * Scoring on structural items that have a label and optional description. + */ +export interface IItemScore { + /** + * Overall score. + */ + score: number + + /** + * Matches within the label. + */ + labelMatch?: IMatch[] + + /** + * Matches within the description. + */ + descriptionMatch?: IMatch[] +} + +const NO_ITEM_SCORE: IItemScore = Object.freeze({ score: 0 }) + +export interface IItemAccessor { + /** + * Just the label of the item to score on. + */ + getItemLabel(item: T): string + + /** + * The optional description of the item to score on. Can be null. + */ + getItemDescription(item: T): string + + /** + * If the item is a file, the path of the file to score on. Can be null. + */ + getItemPath(file: T): string +} + +const PATH_IDENTITY_SCORE = 1 << 18 +const LABEL_PREFIX_SCORE = 1 << 17 +const LABEL_CAMELCASE_SCORE = 1 << 16 +const LABEL_SCORE_THRESHOLD = 1 << 15 + +export interface IPreparedQuery { + original: string + value: string + lowercase: string + containsPathSeparator: boolean +} + +/** + * Helper function to prepare a search value for scoring in quick open by removing unwanted characters. + */ +export function prepareQuery(original: string): IPreparedQuery { + let lowercase: string + let containsPathSeparator: boolean + let value: string + + if (original) { + value = stripWildcards(original).replace(/\s/g, "") // get rid of all wildcards and whitespace + if (isWindows) { + value = value.replace(/\//g, nativeSep) // Help Windows users to search for paths when using slash + } + + lowercase = value.toLowerCase() + containsPathSeparator = value.indexOf(nativeSep) >= 0 + } + + return { original, value, lowercase, containsPathSeparator } +} + +export function scoreItem( + item: T, + query: IPreparedQuery, + fuzzy: boolean, + accessor: IItemAccessor, + // cache: ScorerCache, +): IItemScore { + if (!item || !query.value) { + return NO_ITEM_SCORE // we need an item and query to score on at least + } + + const label = accessor.getItemLabel(item) + if (!label) { + return NO_ITEM_SCORE // we need a label at least + } + + const description = accessor.getItemDescription(item) + + // let cacheHash: string + // if (description) { + // cacheHash = `${label}${description}${query.value}${fuzzy}` + // } else { + // cacheHash = `${label}${query.value}${fuzzy}` + // } + + // const cached = cache[cacheHash] + // if (cached) { + // return cached + // } + + const itemScore = doScoreItem(label, description, accessor.getItemPath(item), query, fuzzy) + // cache[cacheHash] = itemScore + + return itemScore +} + +function doScoreItem( + label: string, + description: string, + path: string, + query: IPreparedQuery, + fuzzy: boolean, +): IItemScore { + // 1.) treat identity matches on full path highest + if (path && isLinux ? query.original === path : equalsIgnoreCase(query.original, path)) { + return { + score: PATH_IDENTITY_SCORE, + labelMatch: [{ start: 0, end: label.length }], + descriptionMatch: description ? [{ start: 0, end: description.length }] : void 0, + } + } + + // We only consider label matches if the query is not including file path separators + const preferLabelMatches = !path || !query.containsPathSeparator + if (preferLabelMatches) { + // 2.) treat prefix matches on the label second highest + const prefixLabelMatch = matchesPrefix(query.value, label) + if (prefixLabelMatch) { + return { score: LABEL_PREFIX_SCORE, labelMatch: prefixLabelMatch } + } + + // 3.) treat camelcase matches on the label third highest + const camelcaseLabelMatch = matchesCamelCase(query.value, label) + if (camelcaseLabelMatch) { + return { score: LABEL_CAMELCASE_SCORE, labelMatch: camelcaseLabelMatch } + } + + // 4.) prefer scores on the label if any + const [labelScore, labelPositions] = score(label, query.value, query.lowercase, fuzzy) + if (labelScore) { + return { + score: labelScore + LABEL_SCORE_THRESHOLD, + labelMatch: createMatches(labelPositions), + } + } + } + + // 5.) finally compute description + label scores if we have a description + if (description) { + let descriptionPrefix = description + if (!!path) { + descriptionPrefix = `${description}${nativeSep}` // assume this is a file path + } + + const descriptionPrefixLength = descriptionPrefix.length + const descriptionAndLabel = `${descriptionPrefix}${label}` + + const [labelDescriptionScore, labelDescriptionPositions] = score( + descriptionAndLabel, + query.value, + query.lowercase, + fuzzy, + ) + if (labelDescriptionScore) { + const labelDescriptionMatches = createMatches(labelDescriptionPositions) + const labelMatch: IMatch[] = [] + const descriptionMatch: IMatch[] = [] + + // We have to split the matches back onto the label and description portions + labelDescriptionMatches.forEach(h => { + // Match overlaps label and description part, we need to split it up + if (h.start < descriptionPrefixLength && h.end > descriptionPrefixLength) { + labelMatch.push({ start: 0, end: h.end - descriptionPrefixLength }) + descriptionMatch.push({ start: h.start, end: descriptionPrefixLength }) + } else if (h.start >= descriptionPrefixLength) { + // Match on label part + labelMatch.push({ + start: h.start - descriptionPrefixLength, + end: h.end - descriptionPrefixLength, + }) + } else { + // Match on description part + descriptionMatch.push(h) + } + }) + + return { score: labelDescriptionScore, labelMatch, descriptionMatch } + } + } + + return NO_ITEM_SCORE +} + +export function compareItemsByScore( + itemA: T, + itemB: T, + query: IPreparedQuery, + fuzzy: boolean, + accessor: IItemAccessor, + // cache: ScorerCache, + fallbackComparer = fallbackCompare, +): number { + const itemScoreA = scoreItem(itemA, query, fuzzy, accessor) + const itemScoreB = scoreItem(itemB, query, fuzzy, accessor) + + const scoreA = itemScoreA.score + const scoreB = itemScoreB.score + + // 1.) prefer identity matches + if (scoreA === PATH_IDENTITY_SCORE || scoreB === PATH_IDENTITY_SCORE) { + if (scoreA !== scoreB) { + return scoreA === PATH_IDENTITY_SCORE ? -1 : 1 + } + } + + // 2.) prefer label prefix matches + if (scoreA === LABEL_PREFIX_SCORE || scoreB === LABEL_PREFIX_SCORE) { + if (scoreA !== scoreB) { + return scoreA === LABEL_PREFIX_SCORE ? -1 : 1 + } + + const labelA = accessor.getItemLabel(itemA) + const labelB = accessor.getItemLabel(itemB) + + // prefer shorter names when both match on label prefix + if (labelA.length !== labelB.length) { + return labelA.length - labelB.length + } + } + + // 3.) prefer camelcase matches + if (scoreA === LABEL_CAMELCASE_SCORE || scoreB === LABEL_CAMELCASE_SCORE) { + if (scoreA !== scoreB) { + return scoreA === LABEL_CAMELCASE_SCORE ? -1 : 1 + } + + const labelA = accessor.getItemLabel(itemA) + const labelB = accessor.getItemLabel(itemB) + + // prefer more compact camel case matches over longer + const comparedByMatchLength = compareByMatchLength( + itemScoreA.labelMatch, + itemScoreB.labelMatch, + ) + if (comparedByMatchLength !== 0) { + return comparedByMatchLength + } + + // prefer shorter names when both match on label camelcase + if (labelA.length !== labelB.length) { + return labelA.length - labelB.length + } + } + + // 4.) prefer label scores + if (scoreA > LABEL_SCORE_THRESHOLD || scoreB > LABEL_SCORE_THRESHOLD) { + if (scoreB < LABEL_SCORE_THRESHOLD) { + return -1 + } + + if (scoreA < LABEL_SCORE_THRESHOLD) { + return 1 + } + } + + // 5.) compare by score + if (scoreA !== scoreB) { + return scoreA > scoreB ? -1 : 1 + } + + // 6.) scores are identical, prefer more compact matches (label and description) + const itemAMatchDistance = computeLabelAndDescriptionMatchDistance(itemA, itemScoreA, accessor) + const itemBMatchDistance = computeLabelAndDescriptionMatchDistance(itemB, itemScoreB, accessor) + if (itemAMatchDistance && itemBMatchDistance && itemAMatchDistance !== itemBMatchDistance) { + return itemBMatchDistance > itemAMatchDistance ? -1 : 1 + } + + // 7.) at this point, scores are identical and match compactness as well + // for both items so we start to use the fallback compare + return fallbackComparer(itemA, itemB, query, accessor) +} + +function computeLabelAndDescriptionMatchDistance( + item: T, + score: IItemScore, + accessor: IItemAccessor, +): number { + const hasLabelMatches = score.labelMatch && score.labelMatch.length + const hasDescriptionMatches = score.descriptionMatch && score.descriptionMatch.length + + let matchStart: number = -1 + let matchEnd: number = -1 + + // If we have description matches, the start is first of description match + if (hasDescriptionMatches) { + matchStart = score.descriptionMatch[0].start + } else if (hasLabelMatches) { + // Otherwise, the start is the first label match + matchStart = score.labelMatch[0].start + } + + // If we have label match, the end is the last label match + // If we had a description match, we add the length of the description + // as offset to the end to indicate this. + if (hasLabelMatches) { + matchEnd = score.labelMatch[score.labelMatch.length - 1].end + if (hasDescriptionMatches) { + const itemDescription = accessor.getItemDescription(item) + if (itemDescription) { + matchEnd += itemDescription.length + } + } + } else if (hasDescriptionMatches) { + // If we have just a description match, the end is the last description match + matchEnd = score.descriptionMatch[score.descriptionMatch.length - 1].end + } + + return matchEnd - matchStart +} + +function compareByMatchLength(matchesA?: IMatch[], matchesB?: IMatch[]): number { + if ((!matchesA && !matchesB) || (!matchesA.length && !matchesB.length)) { + return 0 // make sure to not cause bad comparing when matches are not provided + } + + if (!matchesB || !matchesB.length) { + return -1 + } + + if (!matchesA || !matchesA.length) { + return 1 + } + + // Compute match length of A (first to last match) + const matchStartA = matchesA[0].start + const matchEndA = matchesA[matchesA.length - 1].end + const matchLengthA = matchEndA - matchStartA + + // Compute match length of B (first to last match) + const matchStartB = matchesB[0].start + const matchEndB = matchesB[matchesB.length - 1].end + const matchLengthB = matchEndB - matchStartB + + // Prefer shorter match length + return matchLengthA === matchLengthB ? 0 : matchLengthB < matchLengthA ? 1 : -1 +} + +export function fallbackCompare( + itemA: T, + itemB: T, + query: IPreparedQuery, + accessor: IItemAccessor, +): number { + // check for label + description length and prefer shorter + const labelA = accessor.getItemLabel(itemA) + const labelB = accessor.getItemLabel(itemB) + + const descriptionA = accessor.getItemDescription(itemA) + const descriptionB = accessor.getItemDescription(itemB) + + const labelDescriptionALength = labelA.length + (descriptionA ? descriptionA.length : 0) + const labelDescriptionBLength = labelB.length + (descriptionB ? descriptionB.length : 0) + + if (labelDescriptionALength !== labelDescriptionBLength) { + return labelDescriptionALength - labelDescriptionBLength + } + + // check for path length and prefer shorter + const pathA = accessor.getItemPath(itemA) + const pathB = accessor.getItemPath(itemB) + + if (pathA && pathB && pathA.length !== pathB.length) { + return pathA.length - pathB.length + } + + // 7.) finally we have equal scores and equal length, we fallback to comparer + + // compare by label + if (labelA !== labelB) { + return compareAnything(labelA, labelB, query.value) + } + + // compare by description + if (descriptionA && descriptionB && descriptionA !== descriptionB) { + return compareAnything(descriptionA, descriptionB, query.value) + } + + // compare by path + if (pathA && pathB && pathA !== pathB) { + return compareAnything(pathA, pathB, query.value) + } + + // equal + return 0 +} diff --git a/browser/src/Services/QuickOpen/Scorer/Utilities.ts b/browser/src/Services/QuickOpen/Scorer/Utilities.ts new file mode 100644 index 0000000000..65d19a3610 --- /dev/null +++ b/browser/src/Services/QuickOpen/Scorer/Utilities.ts @@ -0,0 +1,41 @@ +/** + * Assortment of imported Utility functions from VSCode + */ + +import { CharCode } from "./CharCode" + +export const isWindows = process.platform === "win32" +export const isMacintosh = process.platform === "darwin" +export const isLinux = process.platform === "linux" + +// The native path separator depending on the OS. +export const nativeSep = isWindows ? "\\" : "/" + +export function isLower(code: number): boolean { + return CharCode.a <= code && code <= CharCode.z +} + +export function isUpper(code: number): boolean { + return CharCode.A <= code && code <= CharCode.Z +} + +export function isNumber(code: number): boolean { + return CharCode.Digit0 <= code && code <= CharCode.Digit9 +} + +export function isWhitespace(code: number): boolean { + return ( + code === CharCode.Space || + code === CharCode.Tab || + code === CharCode.LineFeed || + code === CharCode.CarriageReturn + ) +} + +export function isAlphanumeric(code: number): boolean { + return isLower(code) || isUpper(code) || isNumber(code) +} + +export function stripWildcards(pattern: string): string { + return pattern.replace(/\*/g, "") +} diff --git a/browser/src/Services/QuickOpen/Scorer/filters.ts b/browser/src/Services/QuickOpen/Scorer/filters.ts new file mode 100644 index 0000000000..2fd972288d --- /dev/null +++ b/browser/src/Services/QuickOpen/Scorer/filters.ts @@ -0,0 +1,224 @@ +/* tslint:disable */ +/** + * Imported functions from VSCode's filters.ts + */ + +import { startsWithIgnoreCase } from "./strings" +import { isAlphanumeric, isLower, isNumber, isUpper, isWhitespace } from "./Utilities" + +export interface IFilter { + // Returns null if word doesn't match. + (word: string, wordToMatchAgainst: string): IMatch[] +} + +export interface IMatch { + start: number + end: number +} + +export const matchesPrefix: IFilter = _matchesPrefix.bind(undefined, true) + +function _matchesPrefix(ignoreCase: boolean, word: string, wordToMatchAgainst: string): IMatch[] { + if (!wordToMatchAgainst || wordToMatchAgainst.length < word.length) { + return null + } + + let matches: boolean + if (ignoreCase) { + matches = startsWithIgnoreCase(wordToMatchAgainst, word) + } else { + matches = wordToMatchAgainst.indexOf(word) === 0 + } + + if (!matches) { + return null + } + + return word.length > 0 ? [{ start: 0, end: word.length }] : [] +} + +export function createMatches(position: number[]): IMatch[] { + let ret: IMatch[] = [] + if (!position) { + return ret + } + let last: IMatch + for (const pos of position) { + if (last && last.end === pos) { + last.end += 1 + } else { + last = { start: pos, end: pos + 1 } + ret.push(last) + } + } + return ret +} + +function nextAnchor(camelCaseWord: string, start: number): number { + for (let i = start; i < camelCaseWord.length; i++) { + let c = camelCaseWord.charCodeAt(i) + if ( + isUpper(c) || + isNumber(c) || + (i > 0 && !isAlphanumeric(camelCaseWord.charCodeAt(i - 1))) + ) { + return i + } + } + return camelCaseWord.length +} + +function _matchesCamelCase(word: string, camelCaseWord: string, i: number, j: number): IMatch[] { + if (i === word.length) { + return [] + } else if (j === camelCaseWord.length) { + return null + } else if (word[i] !== camelCaseWord[j].toLowerCase()) { + return null + } else { + let result: IMatch[] = null + let nextUpperIndex = j + 1 + result = _matchesCamelCase(word, camelCaseWord, i + 1, j + 1) + while ( + !result && + (nextUpperIndex = nextAnchor(camelCaseWord, nextUpperIndex)) < camelCaseWord.length + ) { + result = _matchesCamelCase(word, camelCaseWord, i + 1, nextUpperIndex) + nextUpperIndex++ + } + return result === null ? null : join({ start: j, end: j + 1 }, result) + } +} + +interface ICamelCaseAnalysis { + upperPercent: number + lowerPercent: number + alphaPercent: number + numericPercent: number +} + +// Heuristic to avoid computing camel case matcher for words that don't +// look like camelCaseWords. +function analyzeCamelCaseWord(word: string): ICamelCaseAnalysis { + let upper = 0, + lower = 0, + alpha = 0, + numeric = 0, + code = 0 + + for (let i = 0; i < word.length; i++) { + code = word.charCodeAt(i) + + if (isUpper(code)) { + upper++ + } + if (isLower(code)) { + lower++ + } + if (isAlphanumeric(code)) { + alpha++ + } + if (isNumber(code)) { + numeric++ + } + } + + let upperPercent = upper / word.length + let lowerPercent = lower / word.length + let alphaPercent = alpha / word.length + let numericPercent = numeric / word.length + + return { upperPercent, lowerPercent, alphaPercent, numericPercent } +} + +function isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean { + const { upperPercent, lowerPercent } = analysis + return lowerPercent === 0 && upperPercent > 0.6 +} + +function isCamelCaseWord(analysis: ICamelCaseAnalysis): boolean { + const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis + return lowerPercent > 0.2 && upperPercent < 0.8 && alphaPercent > 0.6 && numericPercent < 0.2 +} + +// Heuristic to avoid computing camel case matcher for words that don't +// look like camel case patterns. +function isCamelCasePattern(word: string): boolean { + let upper = 0, + lower = 0, + code = 0, + whitespace = 0 + + for (let i = 0; i < word.length; i++) { + code = word.charCodeAt(i) + + if (isUpper(code)) { + upper++ + } + if (isLower(code)) { + lower++ + } + if (isWhitespace(code)) { + whitespace++ + } + } + + if ((upper === 0 || lower === 0) && whitespace === 0) { + return word.length <= 30 + } else { + return upper <= 5 + } +} + +export function matchesCamelCase(word: string, camelCaseWord: string): IMatch[] { + if (!camelCaseWord) { + return null + } + + camelCaseWord = camelCaseWord.trim() + + if (camelCaseWord.length === 0) { + return null + } + + if (!isCamelCasePattern(word)) { + return null + } + + if (camelCaseWord.length > 60) { + return null + } + + const analysis = analyzeCamelCaseWord(camelCaseWord) + + if (!isCamelCaseWord(analysis)) { + if (!isUpperCaseWord(analysis)) { + return null + } + + camelCaseWord = camelCaseWord.toLowerCase() + } + + let result: IMatch[] = null + let i = 0 + + while ( + i < camelCaseWord.length && + (result = _matchesCamelCase(word.toLowerCase(), camelCaseWord, 0, i)) === null + ) { + i = nextAnchor(camelCaseWord, i + 1) + } + + return result +} + +function join(head: IMatch, tail: IMatch[]): IMatch[] { + if (tail.length === 0) { + tail = [head] + } else if (head.end === tail[0].start) { + tail[0].start = head.start + } else { + tail.unshift(head) + } + return tail +} diff --git a/browser/src/Services/QuickOpen/Scorer/strings.ts b/browser/src/Services/QuickOpen/Scorer/strings.ts new file mode 100644 index 0000000000..1f40ca34fe --- /dev/null +++ b/browser/src/Services/QuickOpen/Scorer/strings.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/** + * Imported functions from VSCode's strings.ts + */ + +import { CharCode } from "./CharCode" + +function isLowerAsciiLetter(code: number): boolean { + return code >= CharCode.a && code <= CharCode.z +} + +function isUpperAsciiLetter(code: number): boolean { + return code >= CharCode.A && code <= CharCode.Z +} + +function isAsciiLetter(code: number): boolean { + return isLowerAsciiLetter(code) || isUpperAsciiLetter(code) +} + +export function equalsIgnoreCase(a: string, b: string): boolean { + const len1 = a ? a.length : 0 + const len2 = b ? b.length : 0 + + if (len1 !== len2) { + return false + } + + return doEqualsIgnoreCase(a, b) +} + +function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean { + if (typeof a !== "string" || typeof b !== "string") { + return false + } + + for (let i = 0; i < stopAt; i++) { + const codeA = a.charCodeAt(i) + const codeB = b.charCodeAt(i) + + if (codeA === codeB) { + continue + } + + // a-z A-Z + if (isAsciiLetter(codeA) && isAsciiLetter(codeB)) { + let diff = Math.abs(codeA - codeB) + if (diff !== 0 && diff !== 32) { + return false + } + } else { + // Any other charcode + if ( + String.fromCharCode(codeA).toLowerCase() !== + String.fromCharCode(codeB).toLowerCase() + ) { + return false + } + } + } + + return true +} + +export function startsWithIgnoreCase(str: string, candidate: string): boolean { + const candidateLength = candidate.length + if (candidate.length > str.length) { + return false + } + + return doEqualsIgnoreCase(str, candidate, candidateLength) +} diff --git a/browser/src/Services/QuickOpen/VSCodeFilter.ts b/browser/src/Services/QuickOpen/VSCodeFilter.ts new file mode 100644 index 0000000000..56444293fd --- /dev/null +++ b/browser/src/Services/QuickOpen/VSCodeFilter.ts @@ -0,0 +1,83 @@ +/** + * VSCodeFilter.ts + * + * Implements filtering logic for the menu using the scores module from VSCode. + */ + +import * as sortBy from "lodash/sortBy" + +import * as Oni from "oni-api" + +import { + compareItemsByScoreOni, + getHighlightsFromResult, + scoreItemOni, +} from "./Scorer/OniQuickOpenScorer" + +import { IMenuOptionWithHighlights, shouldFilterbeCaseSensitive } from "./../Menu" + +export const vsCodeFilter = ( + options: Oni.Menu.MenuOption[], + searchString: string, +): IMenuOptionWithHighlights[] => { + if (!searchString) { + const opt = options.map(o => { + return { + ...o, + detailHighlights: [], + labelHighlights: [], + } + }) + + return sortBy(opt, o => (o.pinned ? 0 : 1)) + } + + const isCaseSensitive = shouldFilterbeCaseSensitive(searchString) + + if (!isCaseSensitive) { + searchString = searchString.toLowerCase() + } + + const listOfSearchTerms = searchString.split(" ").filter(x => x) + + // Since the VSCode scorer doesn't deal so well with the spaces, + // instead rebuild the term in reverse order. + // ie `index browser editor` becomes `browsereditorindex` + // This allows the scoring and highlighting to work better. + const vsCodeSearchString = + listOfSearchTerms.length > 1 + ? listOfSearchTerms.slice(1).join("") + listOfSearchTerms[0] + : listOfSearchTerms[0] + + const filteredOptions = processSearchTerm(vsCodeSearchString, options) + + const ret = filteredOptions.filter(fo => { + if (fo.score === 0) { + return false + } else { + return true + } + }) + + return ret.sort((e1, e2) => compareItemsByScoreOni(e1, e2, vsCodeSearchString, true)) +} + +export const processSearchTerm = ( + searchString: string, + options: Oni.Menu.MenuOption[], +): Oni.Menu.IMenuOptionWithHighlights[] => { + const result: Oni.Menu.IMenuOptionWithHighlights[] = options.map(f => { + const itemScore = scoreItemOni(f, searchString, true) + const detailHighlights = getHighlightsFromResult(itemScore.descriptionMatch) + const labelHighlights = getHighlightsFromResult(itemScore.labelMatch) + + return { + ...f, + detailHighlights, + labelHighlights, + score: f.pinned ? Number.MAX_SAFE_INTEGER : itemScore.score, + } + }) + + return result +} diff --git a/browser/test/Services/QuickOpen/RegExFilterTests.ts b/browser/test/Services/QuickOpen/RegExFilterTests.ts index c548e1d0ae..d4c6301c1f 100644 --- a/browser/test/Services/QuickOpen/RegExFilterTests.ts +++ b/browser/test/Services/QuickOpen/RegExFilterTests.ts @@ -66,6 +66,7 @@ describe("regexFilter", () => { result.forEach(r => { delete r.detailHighlights delete r.labelHighlights + delete r.score }) const expectedResult = [ @@ -88,6 +89,7 @@ describe("regexFilter", () => { // elsewhere. delete result[0].detailHighlights delete result[0].labelHighlights + delete result[0].score const expectedResult = [{ label: "index.ts", detail: "browser/src/index.ts" }] @@ -106,6 +108,7 @@ describe("regexFilter", () => { // elsewhere. delete result[0].detailHighlights delete result[0].labelHighlights + delete result[0].score const expectedResult = [ { label: "index.ts", detail: "browser/src/services/quickopen/index.ts" }, diff --git a/browser/test/Services/QuickOpen/VSCodeFilterTests.ts b/browser/test/Services/QuickOpen/VSCodeFilterTests.ts new file mode 100644 index 0000000000..a1f36c3233 --- /dev/null +++ b/browser/test/Services/QuickOpen/VSCodeFilterTests.ts @@ -0,0 +1,287 @@ +/** + * VSCodeFilterTests.ts + */ + +import * as assert from "assert" +import { processSearchTerm, vsCodeFilter } from "./../../../src/Services/QuickOpen/VSCodeFilter" + +describe("processSearchTerm", () => { + it("Correctly matches word.", async () => { + const testString = "src" + const testList = [ + { label: "index.ts", detail: "browser/src" }, + { label: "index.ts", detail: "browser/test" }, + ] + + const result = processSearchTerm(testString, testList) + const filteredResult = result.filter(r => r.score !== 0) + + // Remove the score since it can change if we updated the + // module. As long as its not 0 that is enough here. + assert.equal(result[0].score > 0, true) + delete result[0].score + + const expectedResult = [ + { + label: "index.ts", + labelHighlights: [] as number[], + detail: "browser/src", + detailHighlights: [8, 9, 10], + }, + ] + + assert.deepEqual(filteredResult, expectedResult) + }) + it("Correctly score case-match higher", async () => { + const testString = "SRC" + const testList = [ + { label: "index.ts", detail: "browser/src" }, + { label: "index.ts", detail: "browser/SRC" }, + ] + + const result = processSearchTerm(testString, testList) + + // Check the exact case match scores higher + const lowercase = result.find(r => r.detail === "browser/src") + const uppercase = result.find(r => r.detail === "browser/SRC") + assert.equal(uppercase.score > lowercase.score, true) + + // Both should be highlighted though + assert.deepEqual(uppercase.detailHighlights, [8, 9, 10]) + assert.deepEqual(lowercase.detailHighlights, [8, 9, 10]) + }) + it("Correctly returns no matches.", async () => { + const testString = "zzz" + const testList = [ + { label: "index.ts", detail: "browser/src" }, + { label: "index.ts", detail: "browser/test" }, + ] + + const result = processSearchTerm(testString, testList) + const filteredResult = result.filter(r => r.score !== 0) + + assert.deepEqual(filteredResult, []) + }) +}) + +describe("vsCodeFilter", () => { + it("Correctly matches string.", async () => { + const testString = "index" + const testList = [ + { label: "index.ts", detail: "browser/src" }, + { label: "main.ts", detail: "browser/src" }, + { label: "index.ts", detail: "browser/test" }, + ] + + const result = vsCodeFilter(testList, testString) + + // Remove the score since it can change if we updated the + // module. + // However, the score should be equal due to an exact match on both. + assert.equal(result[0].score === result[1].score, true) + delete result[0].score + delete result[1].score + + const expectedResult = [ + { + label: "index.ts", + labelHighlights: [0, 1, 2, 3, 4], + detail: "browser/src", + detailHighlights: [] as number[], + }, + { + label: "index.ts", + labelHighlights: [0, 1, 2, 3, 4], + detail: "browser/test", + detailHighlights: [] as number[], + }, + ] + + assert.deepEqual(result, expectedResult) + }) + it("Correctly matches string with extension.", async () => { + const testString = "index.ts" + const testList = [ + { label: "index.ts", detail: "browser/src" }, + { label: "main.ts", detail: "browser/src" }, + { label: "index.ts", detail: "browser/test" }, + ] + + const result = vsCodeFilter(testList, testString) + + // Remove the score since it can change if we updated the + // module. + // However, the score should be equal due to an exact match on both. + assert.equal(result[0].score === result[1].score, true) + delete result[0].score + delete result[1].score + + const expectedResult = [ + { + label: "index.ts", + labelHighlights: [0, 1, 2, 3, 4, 5, 6, 7], + detail: "browser/src", + detailHighlights: [] as number[], + }, + { + label: "index.ts", + labelHighlights: [0, 1, 2, 3, 4, 5, 6, 7], + detail: "browser/test", + detailHighlights: [] as number[], + }, + ] + + assert.deepEqual(result, expectedResult) + }) + it("Correctly splits and matches string.", async () => { + const testString = "index src" + const testList = [ + { label: "index.ts", detail: "browser/src" }, + { label: "index.ts", detail: "browser/test" }, + ] + + const result = vsCodeFilter(testList, testString) + + // Remove the score since it can change if we updated the + // module. As long as its not 0 that is enough here. + assert.equal(result[0].score > 0, true) + delete result[0].score + + const expectedResult = [ + { + label: "index.ts", + labelHighlights: [0, 1, 2, 3, 4], + detail: "browser/src", + detailHighlights: [8, 9, 10], + }, + ] + + assert.deepEqual(result, expectedResult) + }) + it("Correctly matches long split string.", async () => { + const testString = "index src service quickopen" + const testList = [ + { label: "index.ts", detail: "browser/src/services/menu" }, + { label: "index.ts", detail: "browser/src/services/quickopen" }, + ] + + const result = vsCodeFilter(testList, testString) + + // Remove the score since it can change if we updated the + // module. As long as its not 0 that is enough here. + // Similarly, the highlights has been tested elsewhere, + // and its long here, so just check lengths. + assert.equal(result[0].score > 0, true) + assert.equal(result[0].labelHighlights.length === 5, true) + assert.equal(result[0].detailHighlights.length === 19, true) + delete result[0].score + delete result[0].labelHighlights + delete result[0].detailHighlights + + const expectedResult = [{ label: "index.ts", detail: "browser/src/services/quickopen" }] + + assert.deepEqual(result, expectedResult) + }) + it("Correctly doesn't match.", async () => { + const testString = "zzz" + const testList = [ + { label: "index.ts", detail: "browser/src/services/menu" }, + { label: "index.ts", detail: "browser/src/services/quickopen" }, + ] + + const result = vsCodeFilter(testList, testString) + + assert.deepEqual(result, []) + }) + it("Correctly matches split string in turn.", async () => { + const testString = "index main" + const testList = [ + { label: "index.ts", detail: "browser/src/services/config" }, + { label: "index.ts", detail: "browser/src/services/quickopen" }, + { label: "main.ts", detail: "browser/src/services/menu" }, + ] + + // Should return no results, since the first term should restrict the second + // search to return no results. + const result = vsCodeFilter(testList, testString) + + assert.deepEqual(result, []) + }) + it("Correctly sorts results for fuzzy match.", async () => { + const testString = "aBE" + const testList = [ + { label: "BufferEditor.ts", detail: "packages/demo/src" }, + { label: "BufferEditorContainer.ts", detail: "packages/demo/src" }, + { label: "astBackedEditing.ts", detail: "packages/core/src" }, + ] + + // All results match, but only the last has an exact match on aBE inside the file name. + const result = vsCodeFilter(testList, testString) + + const be = result.find(r => r.label === "BufferEditor.ts") + const bec = result.find(r => r.label === "BufferEditorContainer.ts") + const abe = result.find(r => r.label === "astBackedEditing.ts") + + // Therefore it should score the highest. + assert.equal(abe.score > be.score, true) + assert.equal(abe.score > bec.score, true) + + // It should also be the first in the list + assert.deepEqual(result[0], abe) + }) + it("Correctly sorts results for filtered search.", async () => { + const testString = "buffer test oni" + const testList = [ + { label: "BufferEditor.ts", detail: "packages/demo/src" }, + { label: "BufferEditorContainer.ts", detail: "packages/demo/src" }, + { label: "BufferEditor.ts", detail: "packages/core/src" }, + { label: "BufferEditor.ts", detail: "packages/core/test" }, + { label: "BufferEditor.ts", detail: "packages/core/test/oni" }, + ] + + const result = vsCodeFilter(testList, testString) + + // Should only match the last term + const best = result.find(r => r.detail === "packages/core/test/oni") + assert.deepEqual(result[0], best) + assert.equal(result.length, 1) + }) + it("Correctly sorts results for shortest result on file name.", async () => { + const testString = "main" + const testList = [ + { label: "main.tex", detail: "packages/core/src" }, + { label: "main.tex", detail: "packages/core/test" }, + { label: "main.tex", detail: "packages/core/test/oni" }, + ] + + const result = vsCodeFilter(testList, testString) + + // Should prefer the short path + const best = result.find(r => r.detail === "packages/core/src") + const second = result.find(r => r.detail === "packages/core/test") + const third = result.find(r => r.detail === "packages/core/test/oni") + + // Order should be as follows + assert.deepEqual(result[0], best) + assert.deepEqual(result[1], second) + assert.deepEqual(result[2], third) + }) + it("Correctly sorts results for shortest result on path.", async () => { + const testString = "somepath" + const testList = [ + { label: "fileA.ts", detail: "/some/path" }, + { label: "fileB.ts", detail: "/some/path/longer" }, + { label: "fileC.ts", detail: "packages/core/oni" }, + ] + + const result = vsCodeFilter(testList, testString) + + // Should prefer the short path + const best = result.find(r => r.label === "fileA.ts") + const second = result.find(r => r.label === "fileB.ts") + + // Order should be as follows + assert.deepEqual(result[0], best) + assert.deepEqual(result[1], second) + }) +}) diff --git a/package.json b/package.json index fb7e402460..069996729b 100644 --- a/package.json +++ b/package.json @@ -858,7 +858,7 @@ "minimist": "1.2.0", "msgpack-lite": "0.1.26", "ocaml-language-server": "^1.0.27", - "oni-api": "^0.0.41", + "oni-api": "^0.0.42", "oni-neovim-binaries": "0.1.1", "oni-ripgrep": "0.0.4", "oni-types": "0.0.4", From 2f8a1c6a6400302e83926c23d2556bbcc76fa169 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 6 Apr 2018 07:39:27 -0700 Subject: [PATCH 16/59] Add @bfulop as a backer - thank you! :) --- .github/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/config.yml b/.github/config.yml index a92e3a55c0..8ec6ad4a61 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -27,3 +27,4 @@ backers: - 3117205 - 5697723 - 6803419 +- 1718128 From 1ca896f837c97608b3ab842d39dce80df0e18d7e Mon Sep 17 00:00:00 2001 From: Akin Date: Fri, 6 Apr 2018 15:43:18 +0100 Subject: [PATCH 17/59] feature: add config option to have sidebar open by default or not (#2049) --- browser/src/Services/Configuration/DefaultConfiguration.ts | 1 + browser/src/Services/Configuration/IConfigurationValues.ts | 1 + browser/src/Services/Sidebar/index.ts | 3 +++ 3 files changed, 5 insertions(+) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 0f64338aa4..84a55e715d 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -243,6 +243,7 @@ const BaseConfiguration: IConfigurationValues = { "recorder.outputPath": os.tmpdir(), "sidebar.enabled": true, + "sidebar.default.open": true, "sidebar.width": "50px", "sidebar.marks.enabled": false, diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index a9057af45d..ee92886f8d 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -222,6 +222,7 @@ export interface IConfigurationValues { "recorder.copyScreenshotToClipboard": boolean "sidebar.enabled": boolean + "sidebar.default.open": boolean "sidebar.width": string "sidebar.marks.enabled": boolean diff --git a/browser/src/Services/Sidebar/index.ts b/browser/src/Services/Sidebar/index.ts index 61804d48d6..cddc5d2f35 100644 --- a/browser/src/Services/Sidebar/index.ts +++ b/browser/src/Services/Sidebar/index.ts @@ -12,6 +12,9 @@ export * from "./SidebarStore" export const activate = (configuration: Configuration, workspace: Workspace) => { if (configuration.getValue("sidebar.enabled")) { _sidebarManager = new SidebarManager(windowManager) + if (!configuration.getValue("sidebar.default.open")) { + _sidebarManager.toggleSidebarVisibility() + } commandManager.registerCommand({ command: "sidebar.toggle", From d51ca84b9916120679a45ff8808070a0d0ddc563 Mon Sep 17 00:00:00 2001 From: Ryan C Date: Fri, 6 Apr 2018 15:56:13 +0100 Subject: [PATCH 18/59] Add config option for showing reference buffer. (#2048) --- .../Configuration/ConfigurationEditor.ts | 22 ++++++++++++++----- .../Configuration/DefaultConfiguration.ts | 1 + .../Configuration/IConfigurationValues.ts | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/browser/src/Services/Configuration/ConfigurationEditor.ts b/browser/src/Services/Configuration/ConfigurationEditor.ts index 6d44a38a25..35aba1bc16 100644 --- a/browser/src/Services/Configuration/ConfigurationEditor.ts +++ b/browser/src/Services/Configuration/ConfigurationEditor.ts @@ -107,13 +107,23 @@ export class ConfigurationEditManager { } } - // Create the buffer with the list of all the available options - await this._createReadonlyReferenceBuffer() + const showReferenceBuffer = this._configuration.getValue( + "configuration.showReferenceBuffer", + ) - // Open the actual configuration file - await this._editorManager.activeEditor.openFile(normalizedEditFile, { - openMode: Oni.FileOpenMode.VerticalSplit, - }) + if (showReferenceBuffer) { + // Create the buffer with the list of all the available options + await this._createReadonlyReferenceBuffer() + + // Open the actual configuration file + await this._editorManager.activeEditor.openFile(normalizedEditFile, { + openMode: Oni.FileOpenMode.VerticalSplit, + }) + } else { + await this._editorManager.activeEditor.openFile(normalizedEditFile, { + openMode: Oni.FileOpenMode.Edit, + }) + } } private async _createReadonlyReferenceBuffer() { diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 84a55e715d..0aefd84b4b 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -36,6 +36,7 @@ const BaseConfiguration: IConfigurationValues = { "browser.defaultUrl": "https://duckduckgo.com", "configuration.editor": "typescript", + "configuration.showReferenceBuffer": true, "debug.fixedSize": null, "debug.neovimPath": null, diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index ee92886f8d..adb2f58815 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -41,6 +41,7 @@ export interface IConfigurationValues { "editor.split.mode": string "configuration.editor": string + "configuration.showReferenceBuffer": boolean // - textMateHighlighting "editor.textMateHighlighting.enabled": boolean From 66ae52defc875bf98b66fe7bb242a133b79a7c6b Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 6 Apr 2018 11:04:23 -0700 Subject: [PATCH 19/59] Build: Add back minimal caching for AppVeyor (#2052) * Add binary caching for appveyor * Fix cache folder * Check for cached binaries to copy over --- appveyor.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 1713f3d6a1..419613bd72 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,6 +9,9 @@ branches: - master - /^release.*/ +cache: + - .oni_build_cache -> package.json + platform: - x86 - x64 @@ -25,6 +28,7 @@ install: - npm --version # install modules - yarn install --verbose + - npm run check-cached-binaries artifacts: - path: dist/*.exe From a99544bdffbceb07c86a1f8c0da614ef7c2e4f52 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 6 Apr 2018 12:35:51 -0700 Subject: [PATCH 20/59] Add commit id when uploading builds (#2053) --- build/script/UploadDistributionBuildsToAzure.js | 1 + 1 file changed, 1 insertion(+) diff --git a/build/script/UploadDistributionBuildsToAzure.js b/build/script/UploadDistributionBuildsToAzure.js index a2e78f1faf..4732b4eff6 100644 --- a/build/script/UploadDistributionBuildsToAzure.js +++ b/build/script/UploadDistributionBuildsToAzure.js @@ -129,6 +129,7 @@ const generateBuildMetadata = (branch, version) => { return { branch, version, + commit: COMMIT_ID, releaseNotesUrl: "https://github.com/onivim/oni/wiki/Whats-New-in-Oni", releaseDate: new Date().getTime(), containerName: getContainerName(branch, version, COMMIT_ID), From 48d55d9b7444d045ce364aeba151e90541e3344e Mon Sep 17 00:00:00 2001 From: Akin Date: Sat, 7 Apr 2018 17:28:23 +0100 Subject: [PATCH 21/59] add textmate grammar for java (#2061) --- .../Configuration/DefaultConfiguration.ts | 4 + extensions/java/syntaxes/Java.tmLanguage.json | 1431 +++++++++++++++++ 2 files changed, 1435 insertions(+) create mode 100644 extensions/java/syntaxes/Java.tmLanguage.json diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 0aefd84b4b..0de02f191d 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -213,6 +213,10 @@ const BaseConfiguration: IConfigurationValues = { "TypeScriptReact.tmLanguage.json", ), }, + "language.java.textMateGrammar": { + ".java": path.join(__dirname, "extensions", "java", "syntaxes", "Java.tmLanguage.json"), + ".jar": path.join(__dirname, "extensions", "java", "syntaxes", "Java.tmLanguage.json"), + }, "language.javascript.completionTriggerCharacters": [".", "/", "\\"], "language.javascript.textMateGrammar": { ".js": path.join( diff --git a/extensions/java/syntaxes/Java.tmLanguage.json b/extensions/java/syntaxes/Java.tmLanguage.json new file mode 100644 index 0000000000..23aeeb748a --- /dev/null +++ b/extensions/java/syntaxes/Java.tmLanguage.json @@ -0,0 +1,1431 @@ +{ + "scopeName": "source.java", + "name": "Java", + "fileTypes": ["java", "bsh"], + "patterns": [ + { + "begin": "\\b(package)\\b\\s*", + "beginCaptures": { + "1": { + "name": "keyword.other.package.java" + } + }, + "end": "\\s*(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.java" + } + }, + "name": "meta.package.java", + "contentName": "storage.modifier.package.java", + "patterns": [ + { + "include": "#comments" + }, + { + "match": "(?<=\\.)\\s*\\.|\\.(?=\\s*;)", + "name": "invalid.illegal.character_not_allowed_here.java" + }, + { + "match": "(?", + "endCaptures": { + "0": { + "name": "punctuation.bracket.angle.java" + } + }, + "patterns": [ + { + "match": "\\b(extends|super)\\b", + "name": "storage.modifier.$1.java" + }, + { + "match": "(?>>?|~|\\^)", + "name": "keyword.operator.bitwise.java" + }, + { + "match": "((&|\\^|\\||<<|>>>?)=)", + "name": "keyword.operator.assignment.bitwise.java" + }, + { + "match": "(===?|!=|<=|>=|<>|<|>)", + "name": "keyword.operator.comparison.java" + }, + { + "match": "([+*/%-]=)", + "name": "keyword.operator.assignment.arithmetic.java" + }, + { + "match": "(=)", + "name": "keyword.operator.assignment.java" + }, + { + "match": "(\\-\\-|\\+\\+)", + "name": "keyword.operator.increment-decrement.java" + }, + { + "match": "(\\-|\\+|\\*|\\/|%)", + "name": "keyword.operator.arithmetic.java" + }, + { + "match": "(!|&&|\\|\\|)", + "name": "keyword.operator.logical.java" + }, + { + "match": "(\\||&)", + "name": "keyword.operator.bitwise.java" + }, + { + "match": "\\b(const|goto)\\b", + "name": "keyword.reserved.java" + } + ] + }, + "lambda-expression": { + "patterns": [ + { + "match": "->", + "name": "storage.type.function.arrow.java" + } + ] + }, + "method-call": { + "begin": "(\\.)\\s*([A-Za-z_$][\\w$]*)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.separator.period.java" + }, + "2": { + "name": "entity.name.function.java" + }, + "3": { + "name": "punctuation.definition.parameters.begin.bracket.round.java" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.java" + } + }, + "name": "meta.method-call.java", + "patterns": [ + { + "include": "#code" + } + ] + }, + "methods": { + "begin": "(?!new)(?=[\\w<].*\\s+)(?=([^=/]|/(?!/))+\\()", + "end": "(})|(?=;)", + "endCaptures": { + "1": { + "name": "punctuation.section.method.end.bracket.curly.java" + } + }, + "name": "meta.method.java", + "patterns": [ + { + "include": "#storage-modifiers" + }, + { + "begin": "(\\w+)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.java" + }, + "2": { + "name": "punctuation.definition.parameters.begin.bracket.round.java" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.java" + } + }, + "name": "meta.method.identifier.java", + "patterns": [ + { + "include": "#parameters" + }, + { + "include": "#parens" + }, + { + "include": "#comments-inline" + } + ] + }, + { + "include": "#generics" + }, + { + "begin": "(?=\\w.*\\s+\\w+\\s*\\()", + "end": "(?=\\s+\\w+\\s*\\()", + "name": "meta.method.return-type.java", + "patterns": [ + { + "include": "#all-types" + }, + { + "include": "#parens" + } + ] + }, + { + "include": "#throws" + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.method.begin.bracket.curly.java" + } + }, + "end": "(?=})", + "contentName": "meta.method.body.java", + "patterns": [ + { + "include": "#code" + } + ] + }, + { + "include": "#comments" + } + ] + }, + "numbers": { + "patterns": [ + { + "match": + "(?x)\n\\b(?)|(?!;)", + "patterns": [ + { + "include": "#generics" + } + ] + }, + { + "match": + "\\b(?:[A-Z]\\w*\\s*(\\.)\\s*)*[A-Z]\\w*\\b((?=\\s*[A-Za-z$_\\n])|(?=\\s*\\.\\.\\.))", + "name": "storage.type.java", + "captures": { + "1": { + "name": "punctuation.separator.period.java" + } + } + } + ] + }, + "object-types-inherited": { + "patterns": [ + { + "include": "#generics" + }, + { + "match": "\\b(?:[A-Z]\\w*\\s*(\\.)\\s*)*[A-Z]\\w*\\b", + "name": "entity.other.inherited-class.java", + "captures": { + "1": { + "name": "punctuation.separator.period.java" + } + } + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.java" + } + ] + }, + "objects": { + "match": "(?(\\w+\\.)*[A-Z]+\\w*) # e.g. `javax.ws.rs.Response`, or `String`\n )\n (\n <[\\w<>,\\.?\\s]*> # e.g. `HashMap`, or `List`\n )?\n (\n (\\[\\])* # int[][]\n )?\n \\s+\n [A-Za-z_$][\\w$]* # At least one identifier after space\n ([\\w\\[\\],$][\\w\\[\\],\\s]*)? # possibly primitive array or additional identifiers\n \\s*(=|;)\n)", + "end": "(?=;)", + "name": "meta.definition.variable.java", + "patterns": [ + { + "match": "([A-Za-z$_][\\w$]*)(?=\\s*(\\[\\])*\\s*(;|=|,))", + "captures": { + "1": { + "name": "variable.other.definition.java" + } + } + }, + { + "include": "#all-types" + }, + { + "begin": "=", + "beginCaptures": { + "0": { + "name": "keyword.operator.assignment.java" + } + }, + "end": "(?=;)", + "patterns": [ + { + "include": "#code" + } + ] + }, + { + "include": "#code" + } + ] + }, + "member-variables": { + "begin": + "(?=private|protected|public|native|synchronized|abstract|threadsafe|transient|static|final)", + "end": "(?=;)", + "patterns": [ + { + "include": "#storage-modifiers" + }, + { + "include": "#variables" + }, + { + "include": "#primitive-arrays" + }, + { + "include": "#object-types" + } + ] + } + } +} From 471244d57ffd9d1f8317962c866f4f2a605d04ce Mon Sep 17 00:00:00 2001 From: Akin Date: Sun, 8 Apr 2018 01:12:36 +0100 Subject: [PATCH 22/59] Feature/add several language grammars (#2068) * add text mate grammar paths to config * fix typo in php name and rename objc filetypes and extensions * add python, sh, zsh * actually add the files * Fix incorrect dir paths for md syntaxes --- .../Configuration/DefaultConfiguration.ts | 118 + .../clojure/syntaxes/clojure.tmLanguage.json | 444 ++ extensions/lua/syntaxes/lua.tmLanguage.json | 282 + .../syntaxes/markdown.tmLanguage.json | 2304 +++++++ .../syntaxes/objective-c++.tmLanguage.json | 19 + .../syntaxes/objective-c.tmLanguage.json | 1016 ++++ extensions/php/syntaxes/html.tmLanguage.json | 89 + extensions/php/syntaxes/php.tmLanguage.json | 3569 +++++++++++ .../python/syntaxes/python.tmLanguage.json | 5368 +++++++++++++++++ extensions/ruby/syntaxes/ruby.tmLanguage.json | 2795 +++++++++ extensions/rust/syntaxes/rust.tmLanguage.json | 662 ++ .../shell/syntaxes/shell.tmLanguage.json | 1287 ++++ .../swift/syntaxes/swift.tmLanguage.json | 229 + 13 files changed, 18182 insertions(+) create mode 100755 extensions/clojure/syntaxes/clojure.tmLanguage.json create mode 100755 extensions/lua/syntaxes/lua.tmLanguage.json create mode 100755 extensions/markdown/syntaxes/markdown.tmLanguage.json create mode 100755 extensions/objective-c/syntaxes/objective-c++.tmLanguage.json create mode 100755 extensions/objective-c/syntaxes/objective-c.tmLanguage.json create mode 100755 extensions/php/syntaxes/html.tmLanguage.json create mode 100755 extensions/php/syntaxes/php.tmLanguage.json create mode 100755 extensions/python/syntaxes/python.tmLanguage.json create mode 100755 extensions/ruby/syntaxes/ruby.tmLanguage.json create mode 100755 extensions/rust/syntaxes/rust.tmLanguage.json create mode 100755 extensions/shell/syntaxes/shell.tmLanguage.json create mode 100755 extensions/swift/syntaxes/swift.tmLanguage.json diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 0de02f191d..3d3a1f03c7 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -213,6 +213,124 @@ const BaseConfiguration: IConfigurationValues = { "TypeScriptReact.tmLanguage.json", ), }, + "language.lua.textMateGrammar": path.join( + __dirname, + "extensions", + "lua", + "syntaxes", + "lua.tmLanguage.json", + ), + "language.clojure.textMateGrammar": path.join( + __dirname, + "extensions", + "clojure", + "syntaxes", + "clojure.tmLanguage.json", + ), + "language.ruby.textMateGrammar": path.join( + __dirname, + "extensions", + "ruby", + "syntaxes", + "ruby.tmLanguage.json", + ), + "language.swift.textMateGrammar": path.join( + __dirname, + "extensions", + "swift", + "syntaxes", + "swift.tmLanguage.json", + ), + "language.rust.textMateGrammar": path.join( + __dirname, + "extensions", + "rust", + "syntaxes", + "rust.tmLanguage.json", + ), + "language.php.textMateGrammar": path.join( + __dirname, + "extensions", + "php", + "syntaxes", + "php.tmLanguage.json", + ), + "language.objc.textMateGrammar": { + ".m": path.join( + __dirname, + "extensions", + "objective-c", + "syntaxes", + "objective-c.tmLanguage.json", + ), + ".h": path.join( + __dirname, + "extensions", + "objective-c", + "syntaxes", + "objective-c.tmLanguage.json", + ), + }, + "language.objcpp.textMateGrammar": { + ".mm": path.join( + __dirname, + "extensions", + "objective-c++", + "syntaxes", + "objective-c++.tmLanguage.json", + ), + }, + "language.python.textMateGrammar": path.join( + __dirname, + "extensions", + "python", + "syntaxes", + "python.tmLanguage.json", + ), + "language.sh.textMateGrammar": path.join( + __dirname, + "extensions", + "shell", + "syntaxes", + "shell.tmLanguage.json", + ), + "language.zsh.textMateGrammar": path.join( + __dirname, + "extensions", + "shell", + "syntaxes", + "shell.tmLanguage.json", + ), + "language.markdown.textMateGrammar": { + ".md": path.join( + __dirname, + "extensions", + "markdown", + "syntaxes", + "markdown.tmLanguage.json", + ), + ".markdown": path.join( + __dirname, + "extensions", + "markdown", + "syntaxes", + "markdown.tmLanguage.json", + ), + ".mkd": path.join( + __dirname, + "extensions", + "markdown", + "syntaxes", + "markdown.tmLanguage.json", + ), + ".mdown": path.join( + __dirname, + "extensions", + "markdown", + "syntaxes", + "markdown.tmLanguage.json", + ), + }, "language.java.textMateGrammar": { ".java": path.join(__dirname, "extensions", "java", "syntaxes", "Java.tmLanguage.json"), ".jar": path.join(__dirname, "extensions", "java", "syntaxes", "Java.tmLanguage.json"), diff --git a/extensions/clojure/syntaxes/clojure.tmLanguage.json b/extensions/clojure/syntaxes/clojure.tmLanguage.json new file mode 100755 index 0000000000..96848424a0 --- /dev/null +++ b/extensions/clojure/syntaxes/clojure.tmLanguage.json @@ -0,0 +1,444 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-clojure/blob/master/grammars/clojure.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-clojure/commit/ecc790326bc8e14220e4d2d72a392a30876c3219", + "name": "Clojure", + "scopeName": "source.clojure", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#shebang-comment" + }, + { + "include": "#quoted-sexp" + }, + { + "include": "#sexp" + }, + { + "include": "#keyfn" + }, + { + "include": "#string" + }, + { + "include": "#vector" + }, + { + "include": "#set" + }, + { + "include": "#map" + }, + { + "include": "#regexp" + }, + { + "include": "#var" + }, + { + "include": "#constants" + }, + { + "include": "#dynamic-variables" + }, + { + "include": "#metadata" + }, + { + "include": "#namespace-symbol" + }, + { + "include": "#symbol" + } + ], + "repository": { + "comment": { + "begin": "(?\\<\\/\\!\\?\\*]+(?=(\\s|\\)|\\]|\\}|\\,))", + "name": "constant.keyword.clojure" + }, + "keyfn": { + "patterns": [ + { + "match": + "(?<=(\\s|\\(|\\[|\\{))(if(-[-a-z\\?]*)?|when(-[-a-z]*)?|for(-[-a-z]*)?|cond|do|let(-[-a-z\\?]*)?|binding|loop|recur|fn|throw[a-z\\-]*|try|catch|finally|([a-z]*case))(?=(\\s|\\)|\\]|\\}))", + "name": "storage.control.clojure" + }, + { + "match": + "(?<=(\\s|\\(|\\[|\\{))(declare-?|(in-)?ns|import|use|require|load|compile|(def[a-z\\-]*))(?=(\\s|\\)|\\]|\\}))", + "name": "keyword.control.clojure" + } + ] + }, + "dynamic-variables": { + "match": "\\*[\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\d]+\\*", + "name": "meta.symbol.dynamic.clojure" + }, + "map": { + "begin": "(\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.section.map.begin.clojure" + } + }, + "end": "(\\}(?=[\\}\\]\\)\\s]*(?:;|$)))|(\\})", + "endCaptures": { + "1": { + "name": "punctuation.section.map.end.trailing.clojure" + }, + "2": { + "name": "punctuation.section.map.end.clojure" + } + }, + "name": "meta.map.clojure", + "patterns": [ + { + "include": "$self" + } + ] + }, + "metadata": { + "patterns": [ + { + "begin": "(\\^\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.section.metadata.map.begin.clojure" + } + }, + "end": "(\\}(?=[\\}\\]\\)\\s]*(?:;|$)))|(\\})", + "endCaptures": { + "1": { + "name": "punctuation.section.metadata.map.end.trailing.clojure" + }, + "2": { + "name": "punctuation.section.metadata.map.end.clojure" + } + }, + "name": "meta.metadata.map.clojure", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "(\\^)", + "end": "(\\s)", + "name": "meta.metadata.simple.clojure", + "patterns": [ + { + "include": "#keyword" + }, + { + "include": "$self" + } + ] + } + ] + }, + "quoted-sexp": { + "begin": "(['``]\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.expression.begin.clojure" + } + }, + "end": "(\\))$|(\\)(?=[\\}\\]\\)\\s]*(?:;|$)))|(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.expression.end.trailing.clojure" + }, + "2": { + "name": "punctuation.section.expression.end.trailing.clojure" + }, + "3": { + "name": "punctuation.section.expression.end.clojure" + } + }, + "name": "meta.quoted-expression.clojure", + "patterns": [ + { + "include": "$self" + } + ] + }, + "regexp": { + "begin": "#\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.regexp.begin.clojure" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.regexp.end.clojure" + } + }, + "name": "string.regexp.clojure", + "patterns": [ + { + "include": "#regexp_escaped_char" + } + ] + }, + "regexp_escaped_char": { + "match": "\\\\.", + "name": "constant.character.escape.clojure" + }, + "set": { + "begin": "(\\#\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.section.set.begin.clojure" + } + }, + "end": "(\\}(?=[\\}\\]\\)\\s]*(?:;|$)))|(\\})", + "endCaptures": { + "1": { + "name": "punctuation.section.set.end.trailing.clojure" + }, + "2": { + "name": "punctuation.section.set.end.clojure" + } + }, + "name": "meta.set.clojure", + "patterns": [ + { + "include": "$self" + } + ] + }, + "sexp": { + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.expression.begin.clojure" + } + }, + "end": "(\\))$|(\\)(?=[\\}\\]\\)\\s]*(?:;|$)))|(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.expression.end.trailing.clojure" + }, + "2": { + "name": "punctuation.section.expression.end.trailing.clojure" + }, + "3": { + "name": "punctuation.section.expression.end.clojure" + } + }, + "name": "meta.expression.clojure", + "patterns": [ + { + "begin": + "(?<=\\()(ns|declare|def[\\w\\d._:+=>\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)", + "name": "entity.global.clojure" + }, + { + "include": "$self" + } + ] + }, + { + "include": "#keyfn" + }, + { + "include": "#constants" + }, + { + "include": "#vector" + }, + { + "include": "#map" + }, + { + "include": "#set" + }, + { + "include": "#sexp" + }, + { + "match": "(?<=\\()(.+?)(?=\\s|\\))", + "captures": { + "1": { + "name": "entity.name.function.clojure" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "include": "$self" + } + ] + }, + "shebang-comment": { + "begin": "^(#!)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.shebang.clojure" + } + }, + "end": "$", + "name": "comment.line.shebang.clojure" + }, + "string": { + "begin": "(?\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)/", + "captures": { + "1": { + "name": "meta.symbol.namespace.clojure" + } + } + } + ] + }, + "symbol": { + "patterns": [ + { + "match": + "([a-zA-Z\\.\\-\\_\\+\\=\\>\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)", + "name": "meta.symbol.clojure" + } + ] + }, + "var": { + "match": + "(?<=(\\s|\\(|\\[|\\{)\\#)'[a-zA-Z0-9\\.\\-\\_\\:\\+\\=\\>\\<\\/\\!\\?\\*]+(?=(\\s|\\)|\\]|\\}))", + "name": "meta.var.clojure" + }, + "vector": { + "begin": "(\\[)", + "beginCaptures": { + "1": { + "name": "punctuation.section.vector.begin.clojure" + } + }, + "end": "(\\](?=[\\}\\]\\)\\s]*(?:;|$)))|(\\])", + "endCaptures": { + "1": { + "name": "punctuation.section.vector.end.trailing.clojure" + }, + "2": { + "name": "punctuation.section.vector.end.clojure" + } + }, + "name": "meta.vector.clojure", + "patterns": [ + { + "include": "$self" + } + ] + } + } +} diff --git a/extensions/lua/syntaxes/lua.tmLanguage.json b/extensions/lua/syntaxes/lua.tmLanguage.json new file mode 100755 index 0000000000..87de56a47c --- /dev/null +++ b/extensions/lua/syntaxes/lua.tmLanguage.json @@ -0,0 +1,282 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/textmate/lua.tmbundle/blob/master/Syntaxes/Lua.plist", + "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/textmate/lua.tmbundle/commit/42da2c6ff5d86c068f72520f856190f413911a80", + "name": "Lua", + "scopeName": "source.lua", + "comment": "Lua Syntax: version 0.8", + "patterns": [ + { + "begin": + "\\b((local\\b)\\s+)?(function)\\s*(\\s+[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)*(:[a-zA-Z_][a-zA-Z0-9_]*)?\\s*)?(\\()", + "beginCaptures": { + "1": { + "name": "storage.modifier.local.lua" + }, + "3": { + "name": "keyword.control.lua" + }, + "4": { + "name": "entity.name.function.lua" + }, + "5": { + "name": "punctuation.definition.parameters.begin.lua" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.lua" + } + }, + "name": "meta.function.lua", + "patterns": [ + { + "match": "[a-zA-Z_][a-zA-Z0-9_]*", + "name": "variable.parameter.function.lua" + } + ] + }, + { + "match": "(?=?|(?) ?", + "captures": { + "2": { + "name": "beginning.punctuation.definition.quote.markdown" + } + }, + "name": "markup.quote.markdown", + "patterns": [ + { + "include": "#block" + } + ], + "while": "(^|\\G)\\s*(>) ?" + }, + "fenced_code_block_css": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(css|css.erb)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.css", + "patterns": [ + { + "include": "source.css" + } + ] + } + ] + }, + "fenced_code_block_basic": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(html|htm|shtml|xhtml|inc|tmpl|tpl)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.html", + "patterns": [ + { + "include": "text.html.basic" + } + ] + } + ] + }, + "fenced_code_block_ini": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ini|conf)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.ini", + "patterns": [ + { + "include": "source.ini" + } + ] + } + ] + }, + "fenced_code_block_java": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(java|bsh)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.java", + "patterns": [ + { + "include": "source.java" + } + ] + } + ] + }, + "fenced_code_block_lua": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(lua)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.lua", + "patterns": [ + { + "include": "source.lua" + } + ] + } + ] + }, + "fenced_code_block_makefile": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(Makefile|makefile|GNUmakefile|OCamlMakefile)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.makefile", + "patterns": [ + { + "include": "source.makefile" + } + ] + } + ] + }, + "fenced_code_block_perl": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl|pl|pm|pod|t|PL|psgi|vcl)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.perl", + "patterns": [ + { + "include": "source.perl" + } + ] + } + ] + }, + "fenced_code_block_r": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(R|r|s|S|Rprofile)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.r", + "patterns": [ + { + "include": "source.r" + } + ] + } + ] + }, + "fenced_code_block_ruby": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ruby|rb|rbx|rjs|Rakefile|rake|cgi|fcgi|gemspec|irbrc|Capfile|ru|prawn|Cheffile|Gemfile|Guardfile|Hobofile|Vagrantfile|Appraisals|Rantfile|Berksfile|Berksfile.lock|Thorfile|Puppetfile)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.ruby", + "patterns": [ + { + "include": "source.ruby" + } + ] + } + ] + }, + "fenced_code_block_php": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(php|php3|php4|php5|phpt|phtml|aw|ctp)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.php", + "patterns": [ + { + "include": "text.html.basic" + }, + { + "include": "source.php" + } + ] + } + ] + }, + "fenced_code_block_sql": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(sql|ddl|dml)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.sql", + "patterns": [ + { + "include": "source.sql" + } + ] + } + ] + }, + "fenced_code_block_vs_net": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(vb)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.vs_net", + "patterns": [ + { + "include": "source.asp.vb.net" + } + ] + } + ] + }, + "fenced_code_block_xml": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xml|xsd|tld|jsp|pt|cpt|dtml|rss|opml)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.xml", + "patterns": [ + { + "include": "text.xml" + } + ] + } + ] + }, + "fenced_code_block_xsl": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xsl|xslt)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.xsl", + "patterns": [ + { + "include": "text.xml.xsl" + } + ] + } + ] + }, + "fenced_code_block_yaml": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(yaml|yml)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.yaml", + "patterns": [ + { + "include": "source.yaml" + } + ] + } + ] + }, + "fenced_code_block_dosbatch": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(bat|batch)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.dosbatch", + "patterns": [ + { + "include": "source.dosbatch" + } + ] + } + ] + }, + "fenced_code_block_clojure": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(clj|cljs|clojure)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.clojure", + "patterns": [ + { + "include": "source.clojure" + } + ] + } + ] + }, + "fenced_code_block_coffee": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(coffee|Cakefile|coffee.erb)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.coffee", + "patterns": [ + { + "include": "source.coffee" + } + ] + } + ] + }, + "fenced_code_block_c": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(c|h)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.c", + "patterns": [ + { + "include": "source.c" + } + ] + } + ] + }, + "fenced_code_block_cpp": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cpp|c\\+\\+|cxx)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.cpp", + "patterns": [ + { + "include": "source.cpp" + } + ] + } + ] + }, + "fenced_code_block_diff": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(patch|diff|rej)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.diff", + "patterns": [ + { + "include": "source.diff" + } + ] + } + ] + }, + "fenced_code_block_dockerfile": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dockerfile|Dockerfile)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.dockerfile", + "patterns": [ + { + "include": "source.dockerfile" + } + ] + } + ] + }, + "fenced_code_block_git_commit": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(COMMIT_EDITMSG|MERGE_MSG)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.git_commit", + "patterns": [ + { + "include": "text.git-commit" + } + ] + } + ] + }, + "fenced_code_block_git_rebase": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(git-rebase-todo)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.git_rebase", + "patterns": [ + { + "include": "text.git-rebase" + } + ] + } + ] + }, + "fenced_code_block_go": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(go|golang)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.go", + "patterns": [ + { + "include": "source.go" + } + ] + } + ] + }, + "fenced_code_block_groovy": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(groovy|gvy)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.groovy", + "patterns": [ + { + "include": "source.groovy" + } + ] + } + ] + }, + "fenced_code_block_jade": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jade|pug)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.jade", + "patterns": [ + { + "include": "text.jade" + } + ] + } + ] + }, + "fenced_code_block_js": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(js|jsx|javascript|es6|mjs)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.javascript", + "patterns": [ + { + "include": "source.js" + } + ] + } + ] + }, + "fenced_code_block_js_regexp": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(regexp)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.js_regexp", + "patterns": [ + { + "include": "source.js.regexp" + } + ] + } + ] + }, + "fenced_code_block_json": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(json|sublime-settings|sublime-menu|sublime-keymap|sublime-mousemap|sublime-theme|sublime-build|sublime-project|sublime-completions)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.json", + "patterns": [ + { + "include": "source.json" + } + ] + } + ] + }, + "fenced_code_block_less": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(less)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.less", + "patterns": [ + { + "include": "source.css.less" + } + ] + } + ] + }, + "fenced_code_block_objc": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(objectivec|objective-c|mm|objc|obj-c|m|h)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.objc", + "patterns": [ + { + "include": "source.objc" + } + ] + } + ] + }, + "fenced_code_block_scss": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scss)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.scss", + "patterns": [ + { + "include": "source.css.scss" + } + ] + } + ] + }, + "fenced_code_block_perl6": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl6|p6|pl6|pm6|nqp)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.perl6", + "patterns": [ + { + "include": "source.perl.6" + } + ] + } + ] + }, + "fenced_code_block_powershell": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(powershell|ps1|psm1|psd1)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.powershell", + "patterns": [ + { + "include": "source.powershell" + } + ] + } + ] + }, + "fenced_code_block_python": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(python|py|py3|rpy|pyw|cpy|SConstruct|Sconstruct|sconstruct|SConscript|gyp|gypi)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.python", + "patterns": [ + { + "include": "source.python" + } + ] + } + ] + }, + "fenced_code_block_regexp_python": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(re)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.regexp_python", + "patterns": [ + { + "include": "source.regexp.python" + } + ] + } + ] + }, + "fenced_code_block_rust": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|rs)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.rust", + "patterns": [ + { + "include": "source.rust" + } + ] + } + ] + }, + "fenced_code_block_scala": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scala|sbt)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.scala", + "patterns": [ + { + "include": "source.scala" + } + ] + } + ] + }, + "fenced_code_block_shell": { + "begin": + "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(shell|sh|bash|zsh|bashrc|bash_profile|bash_login|profile|bash_logout|.textmate_init)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.shellscript", + "patterns": [ + { + "include": "source.shell" + } + ] + } + ] + }, + "fenced_code_block_ts": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(typescript|ts)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.typescript", + "patterns": [ + { + "include": "source.ts" + } + ] + } + ] + }, + "fenced_code_block_tsx": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(tsx)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.typescriptreact", + "patterns": [ + { + "include": "source.tsx" + } + ] + } + ] + }, + "fenced_code_block_csharp": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cs|csharp|c#)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.csharp", + "patterns": [ + { + "include": "source.cs" + } + ] + } + ] + }, + "fenced_code_block_fsharp": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(fs|fsharp|f#)(\\s+[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.fsharp", + "patterns": [ + { + "include": "source.fsharp" + } + ] + } + ] + }, + "fenced_code_block_unknown": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?=([^`~]*)?$)", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language" + } + }, + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "name": "markup.fenced_code.block.markdown" + }, + "heading": { + "begin": "(?:^|\\G)[ ]{0,3}(#{1,6})\\s*(?=[\\S[^#]])", + "captures": { + "1": { + "name": "punctuation.definition.heading.markdown" + } + }, + "contentName": "entity.name.section.markdown", + "end": "\\s*(#{1,6})?$\\n?", + "name": "markup.heading.markdown", + "patterns": [ + { + "include": "#inline" + } + ] + }, + "heading-setext": { + "patterns": [ + { + "match": "^(={3,})(?=[ \\t]*$\\n?)", + "name": "markup.heading.setext.1.markdown" + }, + { + "match": "^(-{3,})(?=[ \\t]*$\\n?)", + "name": "markup.heading.setext.2.markdown" + } + ] + }, + "html": { + "patterns": [ + { + "begin": "(^|\\G)\\s*()", + "name": "comment.block.html" + }, + { + "begin": + "(^|\\G)\\s*(?=<(script|style|pre)(\\s|$|>)(?!.*?))", + "end": "(?=.*)", + "patterns": [ + { + "begin": "(\\s*|$)", + "patterns": [ + { + "include": "text.html.basic" + } + ], + "while": "^(?!.*)" + } + ] + }, + { + "begin": + "(^|\\G)\\s*(?=))", + "patterns": [ + { + "include": "text.html.basic" + } + ], + "while": "^(?!\\s*$)" + }, + { + "begin": + "(^|\\G)\\s*(?=(<[a-zA-Z0-9\\-](/?>|\\s.*?>)|)\\s*$)", + "patterns": [ + { + "include": "text.html.basic" + } + ], + "while": "^(?!\\s*$)" + } + ] + }, + "link-def": { + "captures": { + "1": { + "name": "punctuation.definition.constant.markdown" + }, + "2": { + "name": "constant.other.reference.link.markdown" + }, + "3": { + "name": "punctuation.definition.constant.markdown" + }, + "4": { + "name": "punctuation.separator.key-value.markdown" + }, + "5": { + "name": "punctuation.definition.link.markdown" + }, + "6": { + "name": "markup.underline.link.markdown" + }, + "7": { + "name": "punctuation.definition.link.markdown" + }, + "8": { + "name": "string.other.link.description.title.markdown" + }, + "9": { + "name": "punctuation.definition.string.begin.markdown" + }, + "10": { + "name": "punctuation.definition.string.end.markdown" + }, + "11": { + "name": "string.other.link.description.title.markdown" + }, + "12": { + "name": "punctuation.definition.string.begin.markdown" + }, + "13": { + "name": "punctuation.definition.string.end.markdown" + } + }, + "match": + "(?x)\n \\s* # Leading whitespace\n (\\[)(.+?)(\\])(:) # Reference name\n [ \\t]* # Optional whitespace\n (?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in quotes…\n | ((\").+?(\")) # or in parens.\n )? # Title is optional\n \\s* # Optional whitespace\n $\n", + "name": "meta.link.reference.def.markdown" + }, + "list_paragraph": { + "begin": "(^|\\G)(?=\\S)(?![*+->]\\s|[0-9]+\\.\\s)", + "name": "meta.paragraph.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.basic" + }, + { + "include": "#heading-setext" + } + ], + "while": + "(^|\\G)(?!\\s*$|#|[ ]{0,3}([-*_>][ ]{2,}){3,}[ \\t]*$\\n?|[ ]{0,3}[*+->]|[ ]{0,3}[0-9]+\\.)" + }, + "lists": { + "patterns": [ + { + "begin": "(^|\\G)([ ]{0,3})([*+-])([ ]{1,3}|\\t)", + "beginCaptures": { + "3": { + "name": "beginning.punctuation.definition.list.markdown" + } + }, + "comment": "Currently does not support un-indented second lines.", + "name": "markup.list.unnumbered.markdown", + "patterns": [ + { + "include": "#block" + }, + { + "include": "#list_paragraph" + } + ], + "while": "((^|\\G)([ ]{4}|\\t))|(^[ \\t]*$)" + }, + { + "begin": "(^|\\G)([ ]{0,3})([0-9]+\\.)([ ]{1,3}|\\t)", + "beginCaptures": { + "3": { + "name": "beginning.punctuation.definition.list.markdown" + } + }, + "name": "markup.list.numbered.markdown", + "patterns": [ + { + "include": "#block" + }, + { + "include": "#list_paragraph" + } + ], + "while": "((^|\\G)([ ]{4}|\\t))|(^[ \\t]*$)" + } + ] + }, + "paragraph": { + "begin": "(^|\\G)[ ]{0,3}(?=\\S)", + "name": "meta.paragraph.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.basic" + }, + { + "include": "#heading-setext" + } + ], + "while": "(^|\\G)((?=\\s*[-=]{3,}\\s*$)|[ ]{4,}(?=\\S))" + }, + "raw_block": { + "begin": "(^|\\G)([ ]{4}|\\t)", + "name": "markup.raw.block.markdown", + "while": "(^|\\G)([ ]{4}|\\t)" + }, + "separator": { + "match": "(^|\\G)[ ]{0,3}([*-_])([ ]{0,2}\\2){2,}[ \\t]*$\\n?", + "name": "meta.separator.markdown" + } + } + }, + "frontMatter": { + "begin": "\\A-{3}\\s*$", + "contentName": "meta.embedded.block.frontmatter", + "patterns": [ + { + "include": "source.yaml" + } + ], + "while": "^(?!(-{3}|\\.{3})\\s*$)" + }, + "inline": { + "patterns": [ + { + "include": "#ampersand" + }, + { + "include": "#bracket" + }, + { + "include": "#bold" + }, + { + "include": "#italic" + }, + { + "include": "#raw" + }, + { + "include": "#escape" + }, + { + "include": "#image-inline" + }, + { + "include": "#image-ref" + }, + { + "include": "#link-email" + }, + { + "include": "#link-inet" + }, + { + "include": "#link-inline" + }, + { + "include": "#link-ref" + }, + { + "include": "#link-ref-literal" + } + ], + "repository": { + "ampersand": { + "comment": + "Markdown will convert this for us. We match it so that the HTML grammar will not mark it up as invalid.", + "match": "&(?!([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+);)", + "name": "meta.other.valid-ampersand.markdown" + }, + "bold": { + "begin": + "(?x)\n ((?]*+> # HTML tags\n | (?`+)([^`]|(?!(?(?!`))`)*+\\k\n # Raw\n | \\\\[\\\\`*_{}\\[\\]()#.!+\\->]?+ # Escapes\n | \\[\n (\n (? # Named group\n [^\\[\\]\\\\] # Match most chars\n | \\\\. # Escaped chars\n | \\[ \\g*+ \\] # Nested brackets\n )*+\n \\]\n (\n ( # Reference Link\n [ ]? # Optional space\n \\[[^\\]]*+\\] # Ref name\n )\n | ( # Inline Link\n \\( # Opening paren\n [ \\t]*+ # Optional whitespace\n ? # URL\n [ \\t]*+ # Optional whitespace\n ( # Optional Title\n (?['\"])\n (.*?)\n \\k<title>\n )?\n \\)\n )\n )\n )\n | (?!(?<=\\S)\\1). # Everything besides\n # style closer\n )++\n (?<=\\S)\\1 # Close\n )\n", + "captures": { + "1": { + "name": "punctuation.definition.bold.markdown" + } + }, + "end": "(?<=\\S)(\\1)", + "name": "markup.bold.markdown", + "patterns": [ + { + "applyEndPatternLast": 1, + "begin": "(?=<[^>]*?>)", + "end": "(?<=>)", + "patterns": [ + { + "include": "text.html.basic" + } + ] + }, + { + "include": "#escape" + }, + { + "include": "#ampersand" + }, + { + "include": "#bracket" + }, + { + "include": "#raw" + }, + { + "include": "#bold" + }, + { + "include": "#italic" + }, + { + "include": "#image-inline" + }, + { + "include": "#link-inline" + }, + { + "include": "#link-inet" + }, + { + "include": "#link-email" + }, + { + "include": "#image-ref" + }, + { + "include": "#link-ref-literal" + }, + { + "include": "#link-ref" + } + ] + }, + "bracket": { + "comment": + "Markdown will convert this for us. We match it so that the HTML grammar will not mark it up as invalid.", + "match": "<(?![a-z/?\\$!])", + "name": "meta.other.valid-bracket.markdown" + }, + "escape": { + "match": "\\\\[-`*_#+.!(){}\\[\\]\\\\>]", + "name": "constant.character.escape.markdown" + }, + "image-inline": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.description.markdown" + }, + "4": { + "name": "punctuation.definition.string.end.markdown" + }, + "5": { + "name": "punctuation.definition.metadata.markdown" + }, + "6": { + "name": "punctuation.definition.link.markdown" + }, + "7": { + "name": "markup.underline.link.image.markdown" + }, + "8": { + "name": "punctuation.definition.link.markdown" + }, + "9": { + "name": "string.other.link.description.title.markdown" + }, + "10": { + "name": "punctuation.definition.string.markdown" + }, + "11": { + "name": "punctuation.definition.string.markdown" + }, + "12": { + "name": "string.other.link.description.title.markdown" + }, + "13": { + "name": "punctuation.definition.string.markdown" + }, + "14": { + "name": "punctuation.definition.string.markdown" + }, + "15": { + "name": "punctuation.definition.metadata.markdown" + } + }, + "match": + "(?x)\n (\\!\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n (<?)(\\S+?)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n", + "name": "meta.image.inline.markdown" + }, + "image-ref": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.description.markdown" + }, + "4": { + "name": "punctuation.definition.string.begin.markdown" + }, + "5": { + "name": "punctuation.definition.constant.markdown" + }, + "6": { + "name": "constant.other.reference.link.markdown" + }, + "7": { + "name": "punctuation.definition.constant.markdown" + } + }, + "match": + "(\\!\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])[ ]?(\\[)(.*?)(\\])", + "name": "meta.image.reference.markdown" + }, + "italic": { + "begin": + "(?x) (\\*\\b|\\b_)(?=\\S) # Open\n (?=\n (\n <[^>]*+> # HTML tags\n | (?<raw>`+)([^`]|(?!(?<!`)\\k<raw>(?!`))`)*+\\k<raw>\n # Raw\n | \\\\[\\\\`*_{}\\[\\]()#.!+\\->]?+ # Escapes\n | \\[\n (\n (?<square> # Named group\n [^\\[\\]\\\\] # Match most chars\n | \\\\. # Escaped chars\n | \\[ \\g<square>*+ \\] # Nested brackets\n )*+\n \\]\n (\n ( # Reference Link\n [ ]? # Optional space\n \\[[^\\]]*+\\] # Ref name\n )\n | ( # Inline Link\n \\( # Opening paren\n [ \\t]*+ # Optional whtiespace\n <?(.*?)>? # URL\n [ \\t]*+ # Optional whtiespace\n ( # Optional Title\n (?<title>['\"])\n (.*?)\n \\k<title>\n )?\n \\)\n )\n )\n )\n | \\1\\1 # Must be bold closer\n | (?!(?<=\\S)\\1). # Everything besides\n # style closer\n )++\n (?<=\\S)\\1 # Close\n )\n", + "captures": { + "1": { + "name": "punctuation.definition.italic.markdown" + } + }, + "end": "(?<=\\S)(\\1)((?!\\1)|(?=\\1\\1))", + "name": "markup.italic.markdown", + "patterns": [ + { + "applyEndPatternLast": 1, + "begin": "(?=<[^>]*?>)", + "end": "(?<=>)", + "patterns": [ + { + "include": "text.html.basic" + } + ] + }, + { + "include": "#escape" + }, + { + "include": "#ampersand" + }, + { + "include": "#bracket" + }, + { + "include": "#raw" + }, + { + "include": "#bold" + }, + { + "include": "#image-inline" + }, + { + "include": "#link-inline" + }, + { + "include": "#link-inet" + }, + { + "include": "#link-email" + }, + { + "include": "#image-ref" + }, + { + "include": "#link-ref-literal" + }, + { + "include": "#link-ref" + } + ] + }, + "link-email": { + "captures": { + "1": { + "name": "punctuation.definition.link.markdown" + }, + "2": { + "name": "markup.underline.link.markdown" + }, + "4": { + "name": "punctuation.definition.link.markdown" + } + }, + "match": "(<)((?:mailto:)?[-.\\w]+@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+)(>)", + "name": "meta.link.email.lt-gt.markdown" + }, + "link-inet": { + "captures": { + "1": { + "name": "punctuation.definition.link.markdown" + }, + "2": { + "name": "markup.underline.link.markdown" + }, + "3": { + "name": "punctuation.definition.link.markdown" + } + }, + "match": "(<)((?:https?|ftp)://.*?)(>)", + "name": "meta.link.inet.markdown" + }, + "link-inline": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.title.markdown" + }, + "4": { + "name": "punctuation.definition.string.end.markdown" + }, + "5": { + "name": "punctuation.definition.metadata.markdown" + }, + "6": { + "name": "punctuation.definition.link.markdown" + }, + "7": { + "name": "markup.underline.link.markdown" + }, + "8": { + "name": "punctuation.definition.link.markdown" + }, + "9": { + "name": "string.other.link.description.title.markdown" + }, + "10": { + "name": "punctuation.definition.string.begin.markdown" + }, + "11": { + "name": "punctuation.definition.string.end.markdown" + }, + "12": { + "name": "string.other.link.description.title.markdown" + }, + "13": { + "name": "punctuation.definition.string.begin.markdown" + }, + "14": { + "name": "punctuation.definition.string.end.markdown" + }, + "15": { + "name": "punctuation.definition.metadata.markdown" + } + }, + "match": + "(?x)\n (\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n (<?)(.*?)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n", + "name": "meta.link.inline.markdown" + }, + "link-ref": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.title.markdown" + }, + "4": { + "name": "punctuation.definition.string.end.markdown" + }, + "5": { + "name": "punctuation.definition.constant.begin.markdown" + }, + "6": { + "name": "constant.other.reference.link.markdown" + }, + "7": { + "name": "punctuation.definition.constant.end.markdown" + } + }, + "match": + "(\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])(\\[)([^\\]]*+)(\\])", + "name": "meta.link.reference.markdown" + }, + "link-ref-literal": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.title.markdown" + }, + "4": { + "name": "punctuation.definition.string.end.markdown" + }, + "5": { + "name": "punctuation.definition.constant.begin.markdown" + }, + "6": { + "name": "punctuation.definition.constant.end.markdown" + } + }, + "match": + "(\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])[ ]?(\\[)(\\])", + "name": "meta.link.reference.literal.markdown" + }, + "raw": { + "captures": { + "1": { + "name": "punctuation.definition.raw.markdown" + }, + "3": { + "name": "punctuation.definition.raw.markdown" + } + }, + "match": "(`+)([^`]|(?!(?<!`)\\1(?!`))`)*+(\\1)", + "name": "markup.inline.raw.string.markdown" + } + } + } + } +} diff --git a/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json b/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json new file mode 100755 index 0000000000..52f5d7206a --- /dev/null +++ b/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json @@ -0,0 +1,19 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-objective-c/blob/master/grammars/objective-c%2B%2B.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-objective-c/commit/7fdf0c40ec1d592a902ed6a7cf5565bdf12e2ae8", + "name": "Objective-C++", + "scopeName": "source.objcpp", + "patterns": [ + { + "include": "source.cpp" + }, + { + "include": "source.objc" + } + ] +} diff --git a/extensions/objective-c/syntaxes/objective-c.tmLanguage.json b/extensions/objective-c/syntaxes/objective-c.tmLanguage.json new file mode 100755 index 0000000000..3587ecaace --- /dev/null +++ b/extensions/objective-c/syntaxes/objective-c.tmLanguage.json @@ -0,0 +1,1016 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-objective-c/blob/master/grammars/objective-c.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-objective-c/commit/0727e04544f3414c1c339cf15a39a05ea3938cb4", + "name": "Objective-C", + "scopeName": "source.objc", + "patterns": [ + { + "begin": + "((@)(interface|protocol))(?!.+;)\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*((:)(?:\\s*)([A-Za-z][A-Za-z0-9]*))?(\\s|\\n)?", + "captures": { + "1": { + "name": "storage.type.objc" + }, + "2": { + "name": "punctuation.definition.storage.type.objc" + }, + "4": { + "name": "entity.name.type.objc" + }, + "6": { + "name": "punctuation.definition.entity.other.inherited-class.objc" + }, + "7": { + "name": "entity.other.inherited-class.objc" + }, + "8": { + "name": "meta.divider.objc" + }, + "9": { + "name": "meta.inherited-class.objc" + } + }, + "contentName": "meta.scope.interface.objc", + "end": "((@)end)\\b", + "name": "meta.interface-or-protocol.objc", + "patterns": [ + { + "include": "#interface_innards" + } + ] + }, + { + "begin": + "((@)(implementation))\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*(?::\\s*([A-Za-z][A-Za-z0-9]*))?", + "captures": { + "1": { + "name": "storage.type.objc" + }, + "2": { + "name": "punctuation.definition.storage.type.objc" + }, + "4": { + "name": "entity.name.type.objc" + }, + "5": { + "name": "entity.other.inherited-class.objc" + } + }, + "contentName": "meta.scope.implementation.objc", + "end": "((@)end)\\b", + "name": "meta.implementation.objc", + "patterns": [ + { + "include": "#implementation_innards" + } + ] + }, + { + "begin": "@\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objc" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objc" + } + }, + "name": "string.quoted.double.objc", + "patterns": [ + { + "include": "source.c#string_escaped_char" + }, + { + "match": + "(?x)%\n\t\t\t\t\t\t(\\d+\\$)? # field (argument #)\n\t\t\t\t\t\t[#0\\- +']* # flags\n\t\t\t\t\t\t((-?\\d+)|\\*(-?\\d+\\$)?)? # minimum field width\n\t\t\t\t\t\t(\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)? # precision\n\t\t\t\t\t\t[@] # conversion type\n\t\t\t\t\t", + "name": "constant.other.placeholder.objc" + }, + { + "include": "source.c#string_placeholder" + } + ] + }, + { + "begin": "\\b(id)\\s*(?=<)", + "beginCaptures": { + "1": { + "name": "storage.type.objc" + } + }, + "end": "(?<=>)", + "name": "meta.id-with-protocol.objc", + "patterns": [ + { + "include": "#protocol_list" + } + ] + }, + { + "match": "\\b(NS_DURING|NS_HANDLER|NS_ENDHANDLER)\\b", + "name": "keyword.control.macro.objc" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objc" + } + }, + "match": "(@)(try|catch|finally|throw)\\b", + "name": "keyword.control.exception.objc" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objc" + } + }, + "match": "(@)(synchronized)\\b", + "name": "keyword.control.synchronize.objc" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objc" + } + }, + "match": "(@)(required|optional)\\b", + "name": "keyword.control.protocol-specification.objc" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objc" + } + }, + "match": "(@)(defs|encode)\\b", + "name": "keyword.other.objc" + }, + { + "match": "\\bid\\b", + "name": "storage.type.id.objc" + }, + { + "match": "\\b(IBOutlet|IBAction|BOOL|SEL|id|unichar|IMP|Class|instancetype)\\b", + "name": "storage.type.objc" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.storage.type.objc" + } + }, + "match": "(@)(class|protocol)\\b", + "name": "storage.type.objc" + }, + { + "begin": "((@)selector)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "storage.type.objc" + }, + "2": { + "name": "punctuation.definition.storage.type.objc" + }, + "3": { + "name": "punctuation.definition.storage.type.objc" + } + }, + "contentName": "meta.selector.method-name.objc", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.storage.type.objc" + } + }, + "name": "meta.selector.objc", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objc" + } + }, + "match": "\\b(?:[a-zA-Z_:][\\w]*)+", + "name": "support.function.any-method.name-of-parameter.objc" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.storage.modifier.objc" + } + }, + "match": "(@)(synchronized|public|package|private|protected)\\b", + "name": "storage.modifier.objc" + }, + { + "match": "\\b(YES|NO|Nil|nil)\\b", + "name": "constant.language.objc" + }, + { + "match": "\\bNSApp\\b", + "name": "support.variable.foundation" + }, + { + "captures": { + "1": { + "name": "punctuation.whitespace.support.function.cocoa.leopard" + }, + "2": { + "name": "support.function.cocoa.leopard" + } + }, + "match": + "(\\s*)\\b(NS(Rect(ToCGRect|FromCGRect)|MakeCollectable|S(tringFromProtocol|ize(ToCGSize|FromCGSize))|Draw(NinePartImage|ThreePartImage)|P(oint(ToCGPoint|FromCGPoint)|rotocolFromString)|EventMaskFromType|Value))\\b" + }, + { + "captures": { + "1": { + "name": "punctuation.whitespace.support.function.leading.cocoa" + }, + "2": { + "name": "support.function.cocoa" + } + }, + "match": + "(\\s*)\\b(NS(R(ound(DownToMultipleOfPageSize|UpToMultipleOfPageSize)|un(CriticalAlertPanel(RelativeToWindow)?|InformationalAlertPanel(RelativeToWindow)?|AlertPanel(RelativeToWindow)?)|e(set(MapTable|HashTable)|c(ycleZone|t(Clip(List)?|F(ill(UsingOperation|List(UsingOperation|With(Grays|Colors(UsingOperation)?))?)?|romString))|ordAllocationEvent)|turnAddress|leaseAlertPanel|a(dPixel|l(MemoryAvailable|locateCollectable))|gisterServicesProvider)|angeFromString)|Get(SizeAndAlignment|CriticalAlertPanel|InformationalAlertPanel|UncaughtExceptionHandler|FileType(s)?|WindowServerMemory|AlertPanel)|M(i(n(X|Y)|d(X|Y))|ouseInRect|a(p(Remove|Get|Member|Insert(IfAbsent|KnownAbsent)?)|ke(R(ect|ange)|Size|Point)|x(Range|X|Y)))|B(itsPer(SampleFromDepth|PixelFromDepth)|e(stDepth|ep|gin(CriticalAlertSheet|InformationalAlertSheet|AlertSheet)))|S(ho(uldRetainWithZone|w(sServicesMenuItem|AnimationEffect))|tringFrom(R(ect|ange)|MapTable|S(ize|elector)|HashTable|Class|Point)|izeFromString|e(t(ShowsServicesMenuItem|ZoneName|UncaughtExceptionHandler|FocusRingStyle)|lectorFromString|archPathForDirectoriesInDomains)|wap(Big(ShortToHost|IntToHost|DoubleToHost|FloatToHost|Long(ToHost|LongToHost))|Short|Host(ShortTo(Big|Little)|IntTo(Big|Little)|DoubleTo(Big|Little)|FloatTo(Big|Little)|Long(To(Big|Little)|LongTo(Big|Little)))|Int|Double|Float|L(ittle(ShortToHost|IntToHost|DoubleToHost|FloatToHost|Long(ToHost|LongToHost))|ong(Long)?)))|H(ighlightRect|o(stByteOrder|meDirectory(ForUser)?)|eight|ash(Remove|Get|Insert(IfAbsent|KnownAbsent)?)|FSType(CodeFromFileType|OfFile))|N(umberOfColorComponents|ext(MapEnumeratorPair|HashEnumeratorItem))|C(o(n(tainsRect|vert(GlyphsToPackedGlyphs|Swapped(DoubleToHost|FloatToHost)|Host(DoubleToSwapped|FloatToSwapped)))|unt(MapTable|HashTable|Frames|Windows(ForContext)?)|py(M(emoryPages|apTableWithZone)|Bits|HashTableWithZone|Object)|lorSpaceFromDepth|mpare(MapTables|HashTables))|lassFromString|reate(MapTable(WithZone)?|HashTable(WithZone)?|Zone|File(namePboardType|ContentsPboardType)))|TemporaryDirectory|I(s(ControllerMarker|EmptyRect|FreedObject)|n(setRect|crementExtraRefCount|te(r(sect(sRect|ionR(ect|ange))|faceStyleForKey)|gralRect)))|Zone(Realloc|Malloc|Name|Calloc|Fr(omPointer|ee))|O(penStepRootDirectory|ffsetRect)|D(i(sableScreenUpdates|videRect)|ottedFrameRect|e(c(imal(Round|Multiply|S(tring|ubtract)|Normalize|Co(py|mpa(ct|re))|IsNotANumber|Divide|Power|Add)|rementExtraRefCountWasZero)|faultMallocZone|allocate(MemoryPages|Object))|raw(Gr(oove|ayBezel)|B(itmap|utton)|ColorTiledRects|TiledRects|DarkBezel|W(hiteBezel|indowBackground)|LightBezel))|U(serName|n(ionR(ect|ange)|registerServicesProvider)|pdateDynamicServices)|Java(Bundle(Setup|Cleanup)|Setup(VirtualMachine)?|Needs(ToLoadClasses|VirtualMachine)|ClassesF(orBundle|romPath)|ObjectNamedInPath|ProvidesClasses)|P(oint(InRect|FromString)|erformService|lanarFromDepth|ageSize)|E(n(d(MapTableEnumeration|HashTableEnumeration)|umerate(MapTable|HashTable)|ableScreenUpdates)|qual(R(ects|anges)|Sizes|Points)|raseRect|xtraRefCount)|F(ileTypeForHFSTypeCode|ullUserName|r(ee(MapTable|HashTable)|ame(Rect(WithWidth(UsingOperation)?)?|Address)))|Wi(ndowList(ForContext)?|dth)|Lo(cationInRange|g(v|PageSize)?)|A(ccessibility(R(oleDescription(ForUIElement)?|aiseBadArgumentException)|Unignored(Children(ForOnlyChild)?|Descendant|Ancestor)|PostNotification|ActionDescription)|pplication(Main|Load)|vailableWindowDepths|ll(MapTable(Values|Keys)|HashTableObjects|ocate(MemoryPages|Collectable|Object)))))\\b" + }, + { + "match": + "\\bNS(RuleEditor|G(arbageCollector|radient)|MapTable|HashTable|Co(ndition|llectionView(Item)?)|T(oolbarItemGroup|extInputClient|r(eeNode|ackingArea))|InvocationOperation|Operation(Queue)?|D(ictionaryController|ockTile)|P(ointer(Functions|Array)|athC(o(ntrol(Delegate)?|mponentCell)|ell(Delegate)?)|r(intPanelAccessorizing|edicateEditor(RowTemplate)?))|ViewController|FastEnumeration|Animat(ionContext|ablePropertyContainer))\\b", + "name": "support.class.cocoa.leopard" + }, + { + "match": + "\\bNS(R(u(nLoop|ler(Marker|View))|e(sponder|cursiveLock|lativeSpecifier)|an(domSpecifier|geSpecifier))|G(etCommand|lyph(Generator|Storage|Info)|raphicsContext)|XML(Node|D(ocument|TD(Node)?)|Parser|Element)|M(iddleSpecifier|ov(ie(View)?|eCommand)|utable(S(tring|et)|C(haracterSet|opying)|IndexSet|D(ictionary|ata)|URLRequest|ParagraphStyle|A(ttributedString|rray))|e(ssagePort(NameServer)?|nu(Item(Cell)?|View)?|t(hodSignature|adata(Item|Query(ResultGroup|AttributeValueTuple)?)))|a(ch(BootstrapServer|Port)|trix))|B(itmapImageRep|ox|u(ndle|tton(Cell)?)|ezierPath|rowser(Cell)?)|S(hadow|c(anner|r(ipt(SuiteRegistry|C(o(ercionHandler|mmand(Description)?)|lassDescription)|ObjectSpecifier|ExecutionContext|WhoseTest)|oll(er|View)|een))|t(epper(Cell)?|atus(Bar|Item)|r(ing|eam))|imple(HorizontalTypesetter|CString)|o(cketPort(NameServer)?|und|rtDescriptor)|p(e(cifierTest|ech(Recognizer|Synthesizer)|ll(Server|Checker))|litView)|e(cureTextField(Cell)?|t(Command)?|archField(Cell)?|rializer|gmentedC(ontrol|ell))|lider(Cell)?|avePanel)|H(ost|TTP(Cookie(Storage)?|URLResponse)|elpManager)|N(ib(Con(nector|trolConnector)|OutletConnector)?|otification(Center|Queue)?|u(ll|mber(Formatter)?)|etService(Browser)?|ameSpecifier)|C(ha(ngeSpelling|racterSet)|o(n(stantString|nection|trol(ler)?|ditionLock)|d(ing|er)|unt(Command|edSet)|pying|lor(Space|P(ick(ing(Custom|Default)|er)|anel)|Well|List)?|m(p(oundPredicate|arisonPredicate)|boBox(Cell)?))|u(stomImageRep|rsor)|IImageRep|ell|l(ipView|o(seCommand|neCommand)|assDescription)|a(ched(ImageRep|URLResponse)|lendar(Date)?)|reateCommand)|T(hread|ypesetter|ime(Zone|r)|o(olbar(Item(Validations)?)?|kenField(Cell)?)|ext(Block|Storage|Container|Tab(le(Block)?)?|Input|View|Field(Cell)?|List|Attachment(Cell)?)?|a(sk|b(le(Header(Cell|View)|Column|View)|View(Item)?))|reeController)|I(n(dex(S(pecifier|et)|Path)|put(Manager|S(tream|erv(iceProvider|er(MouseTracker)?)))|vocation)|gnoreMisspelledWords|mage(Rep|Cell|View)?)|O(ut(putStream|lineView)|pen(GL(Context|Pixel(Buffer|Format)|View)|Panel)|bj(CTypeSerializationCallBack|ect(Controller)?))|D(i(st(antObject(Request)?|ributed(NotificationCenter|Lock))|ctionary|rectoryEnumerator)|ocument(Controller)?|e(serializer|cimalNumber(Behaviors|Handler)?|leteCommand)|at(e(Components|Picker(Cell)?|Formatter)?|a)|ra(wer|ggingInfo))|U(ser(InterfaceValidations|Defaults(Controller)?)|RL(Re(sponse|quest)|Handle(Client)?|C(onnection|ache|redential(Storage)?)|Download(Delegate)?|Prot(ocol(Client)?|ectionSpace)|AuthenticationChallenge(Sender)?)?|n(iqueIDSpecifier|doManager|archiver))|P(ipe|o(sitionalSpecifier|pUpButton(Cell)?|rt(Message|NameServer|Coder)?)|ICTImageRep|ersistentDocument|DFImageRep|a(steboard|nel|ragraphStyle|geLayout)|r(int(Info|er|Operation|Panel)|o(cessInfo|tocolChecker|perty(Specifier|ListSerialization)|gressIndicator|xy)|edicate))|E(numerator|vent|PSImageRep|rror|x(ception|istsCommand|pression))|V(iew(Animation)?|al(idated(ToobarItem|UserInterfaceItem)|ue(Transformer)?))|Keyed(Unarchiver|Archiver)|Qui(ckDrawView|tCommand)|F(ile(Manager|Handle|Wrapper)|o(nt(Manager|Descriptor|Panel)?|rm(Cell|atter)))|W(hoseSpecifier|indow(Controller)?|orkspace)|L(o(c(k(ing)?|ale)|gicalTest)|evelIndicator(Cell)?|ayoutManager)|A(ssertionHandler|nimation|ctionCell|ttributedString|utoreleasePool|TSTypesetter|ppl(ication|e(Script|Event(Manager|Descriptor)))|ffineTransform|lert|r(chiver|ray(Controller)?)))\\b", + "name": "support.class.cocoa" + }, + { + "match": + "\\bNS(R(oundingMode|ule(Editor(RowType|NestingMode)|rOrientation)|e(questUserAttentionType|lativePosition))|G(lyphInscription|radientDrawingOptions)|XML(NodeKind|D(ocumentContentKind|TDNodeKind)|ParserError)|M(ultibyteGlyphPacking|apTableOptions)|B(itmapFormat|oxType|ezierPathElement|ackgroundStyle|rowserDropOperation)|S(tr(ing(CompareOptions|DrawingOptions|EncodingConversionOptions)|eam(Status|Event))|p(eechBoundary|litViewDividerStyle)|e(archPathD(irectory|omainMask)|gmentS(tyle|witchTracking))|liderType|aveOptions)|H(TTPCookieAcceptPolicy|ashTableOptions)|N(otification(SuspensionBehavior|Coalescing)|umberFormatter(RoundingMode|Behavior|Style|PadPosition)|etService(sError|Options))|C(haracterCollection|o(lor(RenderingIntent|SpaceModel|PanelMode)|mp(oundPredicateType|arisonPredicateModifier))|ellStateValue|al(culationError|endarUnit))|T(ypesetterControlCharacterAction|imeZoneNameStyle|e(stComparisonOperation|xt(Block(Dimension|V(erticalAlignment|alueType)|Layer)|TableLayoutAlgorithm|FieldBezelStyle))|ableView(SelectionHighlightStyle|ColumnAutoresizingStyle)|rackingAreaOptions)|I(n(sertionPosition|te(rfaceStyle|ger))|mage(RepLoadStatus|Scaling|CacheMode|FrameStyle|LoadStatus|Alignment))|Ope(nGLPixelFormatAttribute|rationQueuePriority)|Date(Picker(Mode|Style)|Formatter(Behavior|Style))|U(RL(RequestCachePolicy|HandleStatus|C(acheStoragePolicy|redentialPersistence))|Integer)|P(o(stingStyle|int(ingDeviceType|erFunctionsOptions)|pUpArrowPosition)|athStyle|r(int(ing(Orientation|PaginationMode)|erTableStatus|PanelOptions)|opertyList(MutabilityOptions|Format)|edicateOperatorType))|ExpressionType|KeyValue(SetMutationKind|Change)|QTMovieLoopMode|F(indPanel(SubstringMatchType|Action)|o(nt(RenderingMode|FamilyClass)|cusRingPlacement))|W(hoseSubelementIdentifier|ind(ingRule|ow(B(utton|ackingLocation)|SharingType|CollectionBehavior)))|L(ine(MovementDirection|SweepDirection|CapStyle|JoinStyle)|evelIndicatorStyle)|Animation(BlockingMode|Curve))\\b", + "name": "support.type.cocoa.leopard" + }, + { + "match": + "\\bC(I(Sampler|Co(ntext|lor)|Image(Accumulator)?|PlugIn(Registration)?|Vector|Kernel|Filter(Generator|Shape)?)|A(Renderer|MediaTiming(Function)?|BasicAnimation|ScrollLayer|Constraint(LayoutManager)?|T(iledLayer|extLayer|rans(ition|action))|OpenGLLayer|PropertyAnimation|KeyframeAnimation|Layer|A(nimation(Group)?|ction)))\\b", + "name": "support.class.quartz" + }, + { + "match": "\\bC(G(Float|Point|Size|Rect)|IFormat|AConstraintAttribute)\\b", + "name": "support.type.quartz" + }, + { + "match": + "\\bNS(R(ect(Edge)?|ange)|G(lyph(Relation|LayoutMode)?|radientType)|M(odalSession|a(trixMode|p(Table|Enumerator)))|B(itmapImageFileType|orderType|uttonType|ezelStyle|ackingStoreType|rowserColumnResizingType)|S(cr(oll(er(Part|Arrow)|ArrowPosition)|eenAuxiliaryOpaque)|tringEncoding|ize|ocketNativeHandle|election(Granularity|Direction|Affinity)|wapped(Double|Float)|aveOperationType)|Ha(sh(Table|Enumerator)|ndler(2)?)|C(o(ntrol(Size|Tint)|mp(ositingOperation|arisonResult))|ell(State|Type|ImagePosition|Attribute))|T(hreadPrivate|ypesetterGlyphInfo|i(ckMarkPosition|tlePosition|meInterval)|o(ol(TipTag|bar(SizeMode|DisplayMode))|kenStyle)|IFFCompression|ext(TabType|Alignment)|ab(State|leViewDropOperation|ViewType)|rackingRectTag)|ImageInterpolation|Zone|OpenGL(ContextAuxiliary|PixelFormatAuxiliary)|D(ocumentChangeType|atePickerElementFlags|ra(werState|gOperation))|UsableScrollerParts|P(oint|r(intingPageOrder|ogressIndicator(Style|Th(ickness|readInfo))))|EventType|KeyValueObservingOptions|Fo(nt(SymbolicTraits|TraitMask|Action)|cusRingType)|W(indow(OrderingMode|Depth)|orkspace(IconCreationOptions|LaunchOptions)|ritingDirection)|L(ineBreakMode|ayout(Status|Direction))|A(nimation(Progress|Effect)|ppl(ication(TerminateReply|DelegateReply|PrintReply)|eEventManagerSuspensionID)|ffineTransformStruct|lertStyle))\\b", + "name": "support.type.cocoa" + }, + { + "match": "\\bNS(NotFound|Ordered(Ascending|Descending|Same))\\b", + "name": "support.constant.cocoa" + }, + { + "match": "\\bNS(MenuDidBeginTracking|ViewDidUpdateTrackingAreas)?Notification\\b", + "name": "support.constant.notification.cocoa.leopard" + }, + { + "match": + "\\bNS(Menu(Did(RemoveItem|SendAction|ChangeItem|EndTracking|AddItem)|WillSendAction)|S(ystemColorsDidChange|plitView(DidResizeSubviews|WillResizeSubviews))|C(o(nt(extHelpModeDid(Deactivate|Activate)|rolT(intDidChange|extDid(BeginEditing|Change|EndEditing)))|lor(PanelColorDidChange|ListDidChange)|mboBox(Selection(IsChanging|DidChange)|Will(Dismiss|PopUp)))|lassDescriptionNeededForClass)|T(oolbar(DidRemoveItem|WillAddItem)|ext(Storage(DidProcessEditing|WillProcessEditing)|Did(BeginEditing|Change|EndEditing)|View(DidChange(Selection|TypingAttributes)|WillChangeNotifyingTextView))|ableView(Selection(IsChanging|DidChange)|ColumnDid(Resize|Move)))|ImageRepRegistryDidChange|OutlineView(Selection(IsChanging|DidChange)|ColumnDid(Resize|Move)|Item(Did(Collapse|Expand)|Will(Collapse|Expand)))|Drawer(Did(Close|Open)|Will(Close|Open))|PopUpButton(CellWillPopUp|WillPopUp)|View(GlobalFrameDidChange|BoundsDidChange|F(ocusDidChange|rameDidChange))|FontSetChanged|W(indow(Did(Resi(ze|gn(Main|Key))|M(iniaturize|ove)|Become(Main|Key)|ChangeScreen(|Profile)|Deminiaturize|Update|E(ndSheet|xpose))|Will(M(iniaturize|ove)|BeginSheet|Close))|orkspace(SessionDid(ResignActive|BecomeActive)|Did(Mount|TerminateApplication|Unmount|PerformFileOperation|Wake|LaunchApplication)|Will(Sleep|Unmount|PowerOff|LaunchApplication)))|A(ntialiasThresholdChanged|ppl(ication(Did(ResignActive|BecomeActive|Hide|ChangeScreenParameters|U(nhide|pdate)|FinishLaunching)|Will(ResignActive|BecomeActive|Hide|Terminate|U(nhide|pdate)|FinishLaunching))|eEventManagerWillProcessFirstEvent)))Notification\\b", + "name": "support.constant.notification.cocoa" + }, + { + "match": + "\\bNS(RuleEditor(RowType(Simple|Compound)|NestingMode(Si(ngle|mple)|Compound|List))|GradientDraws(BeforeStartingLocation|AfterEndingLocation)|M(inusSetExpressionType|a(chPortDeallocate(ReceiveRight|SendRight|None)|pTable(StrongMemory|CopyIn|ZeroingWeakMemory|ObjectPointerPersonality)))|B(oxCustom|undleExecutableArchitecture(X86|I386|PPC(64)?)|etweenPredicateOperatorType|ackgroundStyle(Raised|Dark|L(ight|owered)))|S(tring(DrawingTruncatesLastVisibleLine|EncodingConversion(ExternalRepresentation|AllowLossy))|ubqueryExpressionType|p(e(ech(SentenceBoundary|ImmediateBoundary|WordBoundary)|llingState(GrammarFlag|SpellingFlag))|litViewDividerStyleThi(n|ck))|e(rvice(RequestTimedOutError|M(iscellaneousError|alformedServiceDictionaryError)|InvalidPasteboardDataError|ErrorM(inimum|aximum)|Application(NotFoundError|LaunchFailedError))|gmentStyle(Round(Rect|ed)|SmallSquare|Capsule|Textured(Rounded|Square)|Automatic)))|H(UDWindowMask|ashTable(StrongMemory|CopyIn|ZeroingWeakMemory|ObjectPointerPersonality))|N(oModeColorPanel|etServiceNoAutoRename)|C(hangeRedone|o(ntainsPredicateOperatorType|l(orRenderingIntent(RelativeColorimetric|Saturation|Default|Perceptual|AbsoluteColorimetric)|lectorDisabledOption))|ellHit(None|ContentArea|TrackableArea|EditableTextArea))|T(imeZoneNameStyle(S(hort(Standard|DaylightSaving)|tandard)|DaylightSaving)|extFieldDatePickerStyle|ableViewSelectionHighlightStyle(Regular|SourceList)|racking(Mouse(Moved|EnteredAndExited)|CursorUpdate|InVisibleRect|EnabledDuringMouseDrag|A(ssumeInside|ctive(In(KeyWindow|ActiveApp)|WhenFirstResponder|Always))))|I(n(tersectSetExpressionType|dexedColorSpaceModel)|mageScale(None|Proportionally(Down|UpOrDown)|AxesIndependently))|Ope(nGLPFAAllowOfflineRenderers|rationQueue(DefaultMaxConcurrentOperationCount|Priority(High|Normal|Very(High|Low)|Low)))|D(iacriticInsensitiveSearch|ownloadsDirectory)|U(nionSetExpressionType|TF(16(BigEndianStringEncoding|StringEncoding|LittleEndianStringEncoding)|32(BigEndianStringEncoding|StringEncoding|LittleEndianStringEncoding)))|P(ointerFunctions(Ma(chVirtualMemory|llocMemory)|Str(ongMemory|uctPersonality)|C(StringPersonality|opyIn)|IntegerPersonality|ZeroingWeakMemory|O(paque(Memory|Personality)|bjectP(ointerPersonality|ersonality)))|at(hStyle(Standard|NavigationBar|PopUp)|ternColorSpaceModel)|rintPanelShows(Scaling|Copies|Orientation|P(a(perSize|ge(Range|SetupAccessory))|review)))|Executable(RuntimeMismatchError|NotLoadableError|ErrorM(inimum|aximum)|L(inkError|oadError)|ArchitectureMismatchError)|KeyValueObservingOption(Initial|Prior)|F(i(ndPanelSubstringMatchType(StartsWith|Contains|EndsWith|FullWord)|leRead(TooLargeError|UnknownStringEncodingError))|orcedOrderingSearch)|Wi(ndow(BackingLocation(MainMemory|Default|VideoMemory)|Sharing(Read(Only|Write)|None)|CollectionBehavior(MoveToActiveSpace|CanJoinAllSpaces|Default))|dthInsensitiveSearch)|AggregateExpressionType)\\b", + "name": "support.constant.cocoa.leopard" + }, + { + "match": + "\\bNS(R(GB(ModeColorPanel|ColorSpaceModel)|ight(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|T(ext(Movement|Alignment)|ab(sBezelBorder|StopType))|ArrowFunctionKey)|ound(RectBezelStyle|Bankers|ed(BezelStyle|TokenStyle|DisclosureBezelStyle)|Down|Up|Plain|Line(CapStyle|JoinStyle))|un(StoppedResponse|ContinuesResponse|AbortedResponse)|e(s(izableWindowMask|et(CursorRectsRunLoopOrdering|FunctionKey))|ce(ssedBezelStyle|iver(sCantHandleCommandScriptError|EvaluationScriptError))|turnTextMovement|doFunctionKey|quiredArgumentsMissingScriptError|l(evancyLevelIndicatorStyle|ative(Before|After))|gular(SquareBezelStyle|ControlSize)|moveTraitFontAction)|a(n(domSubelement|geDateMode)|tingLevelIndicatorStyle|dio(ModeMatrix|Button)))|G(IFFileType|lyph(Below|Inscribe(B(elow|ase)|Over(strike|Below)|Above)|Layout(WithPrevious|A(tAPoint|gainstAPoint))|A(ttribute(BidiLevel|Soft|Inscribe|Elastic)|bove))|r(ooveBorder|eaterThan(Comparison|OrEqualTo(Comparison|PredicateOperatorType)|PredicateOperatorType)|a(y(ModeColorPanel|ColorSpaceModel)|dient(None|Con(cave(Strong|Weak)|vex(Strong|Weak)))|phiteControlTint)))|XML(N(o(tationDeclarationKind|de(CompactEmptyElement|IsCDATA|OptionsNone|Use(SingleQuotes|DoubleQuotes)|Pre(serve(NamespaceOrder|C(haracterReferences|DATA)|DTD|Prefixes|E(ntities|mptyElements)|Quotes|Whitespace|A(ttributeOrder|ll))|ttyPrint)|ExpandEmptyElement))|amespaceKind)|CommentKind|TextKind|InvalidKind|D(ocument(X(MLKind|HTMLKind|Include)|HTMLKind|T(idy(XML|HTML)|extKind)|IncludeContentTypeDeclaration|Validate|Kind)|TDKind)|P(arser(GTRequiredError|XMLDeclNot(StartedError|FinishedError)|Mi(splaced(XMLDeclarationError|CDATAEndStringError)|xedContentDeclNot(StartedError|FinishedError))|S(t(andaloneValueError|ringNot(StartedError|ClosedError))|paceRequiredError|eparatorRequiredError)|N(MTOKENRequiredError|o(t(ationNot(StartedError|FinishedError)|WellBalancedError)|DTDError)|amespaceDeclarationError|AMERequiredError)|C(haracterRef(In(DTDError|PrologError|EpilogError)|AtEOFError)|o(nditionalSectionNot(StartedError|FinishedError)|mment(NotFinishedError|ContainsDoubleHyphenError))|DATANotFinishedError)|TagNameMismatchError|In(ternalError|valid(HexCharacterRefError|C(haracter(RefError|InEntityError|Error)|onditionalSectionError)|DecimalCharacterRefError|URIError|Encoding(NameError|Error)))|OutOfMemoryError|D(ocumentStartError|elegateAbortedParseError|OCTYPEDeclNotFinishedError)|U(RI(RequiredError|FragmentError)|n(declaredEntityError|parsedEntityError|knownEncodingError|finishedTagError))|P(CDATARequiredError|ublicIdentifierRequiredError|arsedEntityRef(MissingSemiError|NoNameError|In(Internal(SubsetError|Error)|PrologError|EpilogError)|AtEOFError)|r(ocessingInstructionNot(StartedError|FinishedError)|ematureDocumentEndError))|E(n(codingNotSupportedError|tity(Ref(In(DTDError|PrologError|EpilogError)|erence(MissingSemiError|WithoutNameError)|LoopError|AtEOFError)|BoundaryError|Not(StartedError|FinishedError)|Is(ParameterError|ExternalError)|ValueRequiredError))|qualExpectedError|lementContentDeclNot(StartedError|FinishedError)|xt(ernalS(tandaloneEntityError|ubsetNotFinishedError)|raContentError)|mptyDocumentError)|L(iteralNot(StartedError|FinishedError)|T(RequiredError|SlashRequiredError)|essThanSymbolInAttributeError)|Attribute(RedefinedError|HasNoValueError|Not(StartedError|FinishedError)|ListNot(StartedError|FinishedError)))|rocessingInstructionKind)|E(ntity(GeneralKind|DeclarationKind|UnparsedKind|P(ar(sedKind|ameterKind)|redefined))|lement(Declaration(MixedKind|UndefinedKind|E(lementKind|mptyKind)|Kind|AnyKind)|Kind))|Attribute(N(MToken(sKind|Kind)|otationKind)|CDATAKind|ID(Ref(sKind|Kind)|Kind)|DeclarationKind|En(tit(yKind|iesKind)|umerationKind)|Kind))|M(i(n(XEdge|iaturizableWindowMask|YEdge|uteCalendarUnit)|terLineJoinStyle|ddleSubelement|xedState)|o(nthCalendarUnit|deSwitchFunctionKey|use(Moved(Mask)?|E(ntered(Mask)?|ventSubtype|xited(Mask)?))|veToBezierPathElement|mentary(ChangeButton|Push(Button|InButton)|Light(Button)?))|enuFunctionKey|a(c(intoshInterfaceStyle|OSRomanStringEncoding)|tchesPredicateOperatorType|ppedRead|x(XEdge|YEdge))|ACHOperatingSystem)|B(MPFileType|o(ttomTabsBezelBorder|ldFontMask|rderlessWindowMask|x(Se(condary|parator)|OldStyle|Primary))|uttLineCapStyle|e(zelBorder|velLineJoinStyle|low(Bottom|Top)|gin(sWith(Comparison|PredicateOperatorType)|FunctionKey))|lueControlTint|ack(spaceCharacter|tabTextMovement|ingStore(Retained|Buffered|Nonretained)|TabCharacter|wardsSearch|groundTab)|r(owser(NoColumnResizing|UserColumnResizing|AutoColumnResizing)|eakFunctionKey))|S(h(ift(JISStringEncoding|KeyMask)|ow(ControlGlyphs|InvisibleGlyphs)|adowlessSquareBezelStyle)|y(s(ReqFunctionKey|tem(D(omainMask|efined(Mask)?)|FunctionKey))|mbolStringEncoding)|c(a(nnedOption|le(None|ToFit|Proportionally))|r(oll(er(NoPart|Increment(Page|Line|Arrow)|Decrement(Page|Line|Arrow)|Knob(Slot)?|Arrows(M(inEnd|axEnd)|None|DefaultSetting))|Wheel(Mask)?|LockFunctionKey)|eenChangedEventType))|t(opFunctionKey|r(ingDrawing(OneShot|DisableScreenFontSubstitution|Uses(DeviceMetrics|FontLeading|LineFragmentOrigin))|eam(Status(Reading|NotOpen|Closed|Open(ing)?|Error|Writing|AtEnd)|Event(Has(BytesAvailable|SpaceAvailable)|None|OpenCompleted|E(ndEncountered|rrorOccurred)))))|i(ngle(DateMode|UnderlineStyle)|ze(DownFontAction|UpFontAction))|olarisOperatingSystem|unOSOperatingSystem|pecialPageOrder|e(condCalendarUnit|lect(By(Character|Paragraph|Word)|i(ng(Next|Previous)|onAffinity(Downstream|Upstream))|edTab|FunctionKey)|gmentSwitchTracking(Momentary|Select(One|Any)))|quareLineCapStyle|witchButton|ave(ToOperation|Op(tions(Yes|No|Ask)|eration)|AsOperation)|mall(SquareBezelStyle|C(ontrolSize|apsFontMask)|IconButtonBezelStyle))|H(ighlightModeMatrix|SBModeColorPanel|o(ur(Minute(SecondDatePickerElementFlag|DatePickerElementFlag)|CalendarUnit)|rizontalRuler|meFunctionKey)|TTPCookieAcceptPolicy(Never|OnlyFromMainDocumentDomain|Always)|e(lp(ButtonBezelStyle|KeyMask|FunctionKey)|avierFontAction)|PUXOperatingSystem)|Year(MonthDa(yDatePickerElementFlag|tePickerElementFlag)|CalendarUnit)|N(o(n(StandardCharacterSetFontMask|ZeroWindingRule|activatingPanelMask|LossyASCIIStringEncoding)|Border|t(ification(SuspensionBehavior(Hold|Coalesce|D(eliverImmediately|rop))|NoCoalescing|CoalescingOn(Sender|Name)|DeliverImmediately|PostToAllSessions)|PredicateType|EqualToPredicateOperatorType)|S(cr(iptError|ollerParts)|ubelement|pecifierError)|CellMask|T(itle|opLevelContainersSpecifierError|abs(BezelBorder|NoBorder|LineBorder))|I(nterfaceStyle|mage)|UnderlineStyle|FontChangeAction)|u(ll(Glyph|CellType)|m(eric(Search|PadKeyMask)|berFormatter(Round(Half(Down|Up|Even)|Ceiling|Down|Up|Floor)|Behavior(10|Default)|S(cientificStyle|pellOutStyle)|NoStyle|CurrencyStyle|DecimalStyle|P(ercentStyle|ad(Before(Suffix|Prefix)|After(Suffix|Prefix))))))|e(t(Services(BadArgumentError|NotFoundError|C(ollisionError|ancelledError)|TimeoutError|InvalidError|UnknownError|ActivityInProgress)|workDomainMask)|wlineCharacter|xt(StepInterfaceStyle|FunctionKey))|EXTSTEPStringEncoding|a(t(iveShortGlyphPacking|uralTextAlignment)|rrowFontMask))|C(hange(ReadOtherContents|GrayCell(Mask)?|BackgroundCell(Mask)?|Cleared|Done|Undone|Autosaved)|MYK(ModeColorPanel|ColorSpaceModel)|ircular(BezelStyle|Slider)|o(n(stantValueExpressionType|t(inuousCapacityLevelIndicatorStyle|entsCellMask|ain(sComparison|erSpecifierError)|rol(Glyph|KeyMask))|densedFontMask)|lor(Panel(RGBModeMask|GrayModeMask|HSBModeMask|C(MYKModeMask|olorListModeMask|ustomPaletteModeMask|rayonModeMask)|WheelModeMask|AllModesMask)|ListModeColorPanel)|reServiceDirectory|m(p(osite(XOR|Source(In|O(ut|ver)|Atop)|Highlight|C(opy|lear)|Destination(In|O(ut|ver)|Atop)|Plus(Darker|Lighter))|ressedFontMask)|mandKeyMask))|u(stom(SelectorPredicateOperatorType|PaletteModeColorPanel)|r(sor(Update(Mask)?|PointingDevice)|veToBezierPathElement))|e(nterT(extAlignment|abStopType)|ll(State|H(ighlighted|as(Image(Horizontal|OnLeftOrBottom)|OverlappingImage))|ChangesContents|Is(Bordered|InsetButton)|Disabled|Editable|LightsBy(Gray|Background|Contents)|AllowsMixedState))|l(ipPagination|o(s(ePathBezierPathElement|ableWindowMask)|ckAndCalendarDatePickerStyle)|ear(ControlTint|DisplayFunctionKey|LineFunctionKey))|a(seInsensitive(Search|PredicateOption)|n(notCreateScriptCommandError|cel(Button|TextMovement))|chesDirectory|lculation(NoError|Overflow|DivideByZero|Underflow|LossOfPrecision)|rriageReturnCharacter)|r(itical(Request|AlertStyle)|ayonModeColorPanel))|T(hick(SquareBezelStyle|erSquareBezelStyle)|ypesetter(Behavior|HorizontalTabAction|ContainerBreakAction|ZeroAdvancementAction|OriginalBehavior|ParagraphBreakAction|WhitespaceAction|L(ineBreakAction|atestBehavior))|i(ckMark(Right|Below|Left|Above)|tledWindowMask|meZoneDatePickerElementFlag)|o(olbarItemVisibilityPriority(Standard|High|User|Low)|pTabsBezelBorder|ggleButton)|IFF(Compression(N(one|EXT)|CCITTFAX(3|4)|OldJPEG|JPEG|PackBits|LZW)|FileType)|e(rminate(Now|Cancel|Later)|xt(Read(InapplicableDocumentTypeError|WriteErrorM(inimum|aximum))|Block(M(i(nimum(Height|Width)|ddleAlignment)|a(rgin|ximum(Height|Width)))|B(o(ttomAlignment|rder)|aselineAlignment)|Height|TopAlignment|P(ercentageValueType|adding)|Width|AbsoluteValueType)|StorageEdited(Characters|Attributes)|CellType|ured(RoundedBezelStyle|BackgroundWindowMask|SquareBezelStyle)|Table(FixedLayoutAlgorithm|AutomaticLayoutAlgorithm)|Field(RoundedBezel|SquareBezel|AndStepperDatePickerStyle)|WriteInapplicableDocumentTypeError|ListPrependEnclosingMarker))|woByteGlyphPacking|ab(Character|TextMovement|le(tP(oint(Mask|EventSubtype)?|roximity(Mask|EventSubtype)?)|Column(NoResizing|UserResizingMask|AutoresizingMask)|View(ReverseSequentialColumnAutoresizingStyle|GridNone|S(olid(HorizontalGridLineMask|VerticalGridLineMask)|equentialColumnAutoresizingStyle)|NoColumnAutoresizing|UniformColumnAutoresizingStyle|FirstColumnOnlyAutoresizingStyle|LastColumnOnlyAutoresizingStyle)))|rackModeMatrix)|I(n(sert(CharFunctionKey|FunctionKey|LineFunctionKey)|t(Type|ernalS(criptError|pecifierError))|dexSubelement|validIndexSpecifierError|formational(Request|AlertStyle)|PredicateOperatorType)|talicFontMask|SO(2022JPStringEncoding|Latin(1StringEncoding|2StringEncoding))|dentityMappingCharacterCollection|llegalTextMovement|mage(R(ight|ep(MatchesDevice|LoadStatus(ReadingHeader|Completed|InvalidData|Un(expectedEOF|knownType)|WillNeedAllData)))|Below|C(ellType|ache(BySize|Never|Default|Always))|Interpolation(High|None|Default|Low)|O(nly|verlaps)|Frame(Gr(oove|ayBezel)|Button|None|Photo)|L(oadStatus(ReadError|C(ompleted|ancelled)|InvalidData|UnexpectedEOF)|eft)|A(lign(Right|Bottom(Right|Left)?|Center|Top(Right|Left)?|Left)|bove)))|O(n(State|eByteGlyphPacking|OffButton|lyScrollerArrows)|ther(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|TextMovement)|SF1OperatingSystem|pe(n(GL(GO(Re(setLibrary|tainRenderers)|ClearFormatCache|FormatCacheSize)|PFA(R(obust|endererID)|M(inimumPolicy|ulti(sample|Screen)|PSafe|aximumPolicy)|BackingStore|S(creenMask|te(ncilSize|reo)|ingleRenderer|upersample|ample(s|Buffers|Alpha))|NoRecovery|C(o(lor(Size|Float)|mpliant)|losestPolicy)|OffScreen|D(oubleBuffer|epthSize)|PixelBuffer|VirtualScreenCount|FullScreen|Window|A(cc(umSize|elerated)|ux(Buffers|DepthStencil)|l(phaSize|lRenderers))))|StepUnicodeReservedBase)|rationNotSupportedForKeyS(criptError|pecifierError))|ffState|KButton|rPredicateType|bjC(B(itfield|oolType)|S(hortType|tr(ingType|uctType)|electorType)|NoType|CharType|ObjectType|DoubleType|UnionType|PointerType|VoidType|FloatType|Long(Type|longType)|ArrayType))|D(i(s(c(losureBezelStyle|reteCapacityLevelIndicatorStyle)|playWindowRunLoopOrdering)|acriticInsensitivePredicateOption|rect(Selection|PredicateModifier))|o(c(ModalWindowMask|ument(Directory|ationDirectory))|ubleType|wn(TextMovement|ArrowFunctionKey))|e(s(cendingPageOrder|ktopDirectory)|cimalTabStopType|v(ice(NColorSpaceModel|IndependentModifierFlagsMask)|eloper(Directory|ApplicationDirectory))|fault(ControlTint|TokenStyle)|lete(Char(acter|FunctionKey)|FunctionKey|LineFunctionKey)|moApplicationDirectory)|a(yCalendarUnit|teFormatter(MediumStyle|Behavior(10|Default)|ShortStyle|NoStyle|FullStyle|LongStyle))|ra(wer(Clos(ingState|edState)|Open(ingState|State))|gOperation(Generic|Move|None|Copy|Delete|Private|Every|Link|All)))|U(ser(CancelledError|D(irectory|omainMask)|FunctionKey)|RL(Handle(NotLoaded|Load(Succeeded|InProgress|Failed))|CredentialPersistence(None|Permanent|ForSession))|n(scaledWindowMask|cachedRead|i(codeStringEncoding|talicFontMask|fiedTitleAndToolbarWindowMask)|d(o(CloseGroupingRunLoopOrdering|FunctionKey)|e(finedDateComponent|rline(Style(Single|None|Thick|Double)|Pattern(Solid|D(ot|ash(Dot(Dot)?)?)))))|known(ColorSpaceModel|P(ointingDevice|ageOrder)|KeyS(criptError|pecifierError))|boldFontMask)|tilityWindowMask|TF8StringEncoding|p(dateWindowsRunLoopOrdering|TextMovement|ArrowFunctionKey))|J(ustifiedTextAlignment|PEG(2000FileType|FileType)|apaneseEUC(GlyphPacking|StringEncoding))|P(o(s(t(Now|erFontMask|WhenIdle|ASAP)|iti(on(Replace|Be(fore|ginning)|End|After)|ve(IntType|DoubleType|FloatType)))|pUp(NoArrow|ArrowAt(Bottom|Center))|werOffEventType|rtraitOrientation)|NGFileType|ush(InCell(Mask)?|OnPushOffButton)|e(n(TipMask|UpperSideMask|PointingDevice|LowerSideMask)|riodic(Mask)?)|P(S(caleField|tatus(Title|Field)|aveButton)|N(ote(Title|Field)|ame(Title|Field))|CopiesField|TitleField|ImageButton|OptionsButton|P(a(perFeedButton|ge(Range(To|From)|ChoiceMatrix))|reviewButton)|LayoutButton)|lainTextTokenStyle|a(useFunctionKey|ragraphSeparatorCharacter|ge(DownFunctionKey|UpFunctionKey))|r(int(ing(ReplyLater|Success|Cancelled|Failure)|ScreenFunctionKey|erTable(NotFound|OK|Error)|FunctionKey)|o(p(ertyList(XMLFormat|MutableContainers(AndLeaves)?|BinaryFormat|Immutable|OpenStepFormat)|rietaryStringEncoding)|gressIndicator(BarStyle|SpinningStyle|Preferred(SmallThickness|Thickness|LargeThickness|AquaThickness)))|e(ssedTab|vFunctionKey))|L(HeightForm|CancelButton|TitleField|ImageButton|O(KButton|rientationMatrix)|UnitsButton|PaperNameButton|WidthForm))|E(n(terCharacter|d(sWith(Comparison|PredicateOperatorType)|FunctionKey))|v(e(nOddWindingRule|rySubelement)|aluatedObjectExpressionType)|qualTo(Comparison|PredicateOperatorType)|ra(serPointingDevice|CalendarUnit|DatePickerElementFlag)|x(clude(10|QuickDrawElementsIconCreationOption)|pandedFontMask|ecuteFunctionKey))|V(i(ew(M(in(XMargin|YMargin)|ax(XMargin|YMargin))|HeightSizable|NotSizable|WidthSizable)|aPanelFontAction)|erticalRuler|a(lidationErrorM(inimum|aximum)|riableExpressionType))|Key(SpecifierEvaluationScriptError|Down(Mask)?|Up(Mask)?|PathExpressionType|Value(MinusSetMutation|SetSetMutation|Change(Re(placement|moval)|Setting|Insertion)|IntersectSetMutation|ObservingOption(New|Old)|UnionSetMutation|ValidationError))|QTMovie(NormalPlayback|Looping(BackAndForthPlayback|Playback))|F(1(1FunctionKey|7FunctionKey|2FunctionKey|8FunctionKey|3FunctionKey|9FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey|6FunctionKey)|7FunctionKey|i(nd(PanelAction(Replace(A(ndFind|ll(InSelection)?))?|S(howFindPanel|e(tFindString|lectAll(InSelection)?))|Next|Previous)|FunctionKey)|tPagination|le(Read(No(SuchFileError|PermissionError)|CorruptFileError|In(validFileNameError|applicableStringEncodingError)|Un(supportedSchemeError|knownError))|HandlingPanel(CancelButton|OKButton)|NoSuchFileError|ErrorM(inimum|aximum)|Write(NoPermissionError|In(validFileNameError|applicableStringEncodingError)|OutOfSpaceError|Un(supportedSchemeError|knownError))|LockingError)|xedPitchFontMask)|2(1FunctionKey|7FunctionKey|2FunctionKey|8FunctionKey|3FunctionKey|9FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey|6FunctionKey)|o(nt(Mo(noSpaceTrait|dernSerifsClass)|BoldTrait|S(ymbolicClass|criptsClass|labSerifsClass|ansSerifClass)|C(o(ndensedTrait|llectionApplicationOnlyMask)|larendonSerifsClass)|TransitionalSerifsClass|I(ntegerAdvancementsRenderingMode|talicTrait)|O(ldStyleSerifsClass|rnamentalsClass)|DefaultRenderingMode|U(nknownClass|IOptimizedTrait)|Panel(S(hadowEffectModeMask|t(andardModesMask|rikethroughEffectModeMask)|izeModeMask)|CollectionModeMask|TextColorEffectModeMask|DocumentColorEffectModeMask|UnderlineEffectModeMask|FaceModeMask|All(ModesMask|EffectsModeMask))|ExpandedTrait|VerticalTrait|F(amilyClassMask|reeformSerifsClass)|Antialiased(RenderingMode|IntegerAdvancementsRenderingMode))|cusRing(Below|Type(None|Default|Exterior)|Only|Above)|urByteGlyphPacking|rm(attingError(M(inimum|aximum))?|FeedCharacter))|8FunctionKey|unction(ExpressionType|KeyMask)|3(1FunctionKey|2FunctionKey|3FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey)|9FunctionKey|4FunctionKey|P(RevertButton|S(ize(Title|Field)|etButton)|CurrentField|Preview(Button|Field))|l(oat(ingPointSamplesBitmapFormat|Type)|agsChanged(Mask)?)|axButton|5FunctionKey|6FunctionKey)|W(heelModeColorPanel|indow(s(NTOperatingSystem|CP125(1StringEncoding|2StringEncoding|3StringEncoding|4StringEncoding|0StringEncoding)|95(InterfaceStyle|OperatingSystem))|M(iniaturizeButton|ovedEventType)|Below|CloseButton|ToolbarButton|ZoomButton|Out|DocumentIconButton|ExposedEventType|Above)|orkspaceLaunch(NewInstance|InhibitingBackgroundOnly|Default|PreferringClassic|WithoutA(ctivation|ddingToRecents)|A(sync|nd(Hide(Others)?|Print)|llowingClassicStartup))|eek(day(CalendarUnit|OrdinalCalendarUnit)|CalendarUnit)|a(ntsBidiLevels|rningAlertStyle)|r(itingDirection(RightToLeft|Natural|LeftToRight)|apCalendarComponents))|L(i(stModeMatrix|ne(Moves(Right|Down|Up|Left)|B(order|reakBy(C(harWrapping|lipping)|Truncating(Middle|Head|Tail)|WordWrapping))|S(eparatorCharacter|weep(Right|Down|Up|Left))|ToBezierPathElement|DoesntMove|arSlider)|teralSearch|kePredicateOperatorType|ghterFontAction|braryDirectory)|ocalDomainMask|e(ssThan(Comparison|OrEqualTo(Comparison|PredicateOperatorType)|PredicateOperatorType)|ft(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|T(ext(Movement|Alignment)|ab(sBezelBorder|StopType))|ArrowFunctionKey))|a(yout(RightToLeft|NotDone|CantFit|OutOfGlyphs|Done|LeftToRight)|ndscapeOrientation)|ABColorSpaceModel)|A(sc(iiWithDoubleByteEUCGlyphPacking|endingPageOrder)|n(y(Type|PredicateModifier|EventMask)|choredSearch|imation(Blocking|Nonblocking(Threaded)?|E(ffect(DisappearingItemDefault|Poof)|ase(In(Out)?|Out))|Linear)|dPredicateType)|t(Bottom|tachmentCharacter|omicWrite|Top)|SCIIStringEncoding|d(obe(GB1CharacterCollection|CNS1CharacterCollection|Japan(1CharacterCollection|2CharacterCollection)|Korea1CharacterCollection)|dTraitFontAction|minApplicationDirectory)|uto(saveOperation|Pagination)|pp(lication(SupportDirectory|D(irectory|e(fined(Mask)?|legateReply(Success|Cancel|Failure)|activatedEventType))|ActivatedEventType)|KitDefined(Mask)?)|l(ternateKeyMask|pha(ShiftKeyMask|NonpremultipliedBitmapFormat|FirstBitmapFormat)|ert(SecondButtonReturn|ThirdButtonReturn|OtherReturn|DefaultReturn|ErrorReturn|FirstButtonReturn|AlternateReturn)|l(ScrollerParts|DomainsMask|PredicateModifier|LibrariesDirectory|ApplicationsDirectory))|rgument(sWrongScriptError|EvaluationScriptError)|bove(Bottom|Top)|WTEventType))\\b", + "name": "support.constant.cocoa" + }, + { + "include": "source.c" + }, + { + "include": "#bracketed_content" + } + ], + "repository": { + "bracketed_content": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.scope.begin.objc" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.scope.end.objc" + } + }, + "name": "meta.bracketed.objc", + "patterns": [ + { + "begin": "(?=predicateWithFormat:)(?<=NSPredicate )(predicateWithFormat:)", + "beginCaptures": { + "1": { + "name": "support.function.any-method.objc" + }, + "2": { + "name": "punctuation.separator.arguments.objc" + } + }, + "end": "(?=\\])", + "name": "meta.function-call.predicate.objc", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objc" + } + }, + "match": "\\bargument(Array|s)(:)", + "name": "support.function.any-method.name-of-parameter.objc" + }, + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objc" + } + }, + "match": "\\b\\w+(:)", + "name": "invalid.illegal.unknown-method.objc" + }, + { + "begin": "@\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objc" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objc" + } + }, + "name": "string.quoted.double.objc", + "patterns": [ + { + "match": "\\b(AND|OR|NOT|IN)\\b", + "name": "keyword.operator.logical.predicate.cocoa" + }, + { + "match": "\\b(ALL|ANY|SOME|NONE)\\b", + "name": "constant.language.predicate.cocoa" + }, + { + "match": + "\\b(NULL|NIL|SELF|TRUE|YES|FALSE|NO|FIRST|LAST|SIZE)\\b", + "name": "constant.language.predicate.cocoa" + }, + { + "match": "\\b(MATCHES|CONTAINS|BEGINSWITH|ENDSWITH|BETWEEN)\\b", + "name": "keyword.operator.comparison.predicate.cocoa" + }, + { + "match": "\\bC(ASEINSENSITIVE|I)\\b", + "name": "keyword.other.modifier.predicate.cocoa" + }, + { + "match": + "\\b(ANYKEY|SUBQUERY|CAST|TRUEPREDICATE|FALSEPREDICATE)\\b", + "name": "keyword.other.predicate.cocoa" + }, + { + "match": + "\\\\(\\\\|[abefnrtv'\"?]|[0-3]\\d{,2}|[4-7]\\d?|x[a-zA-Z0-9]+)", + "name": "constant.character.escape.objc" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unknown-escape.objc" + } + ] + }, + { + "include": "#special_variables" + }, + { + "include": "#c_functions" + }, + { + "include": "$base" + } + ] + }, + { + "begin": "(?=\\w)(?<=[\\w\\])\"] )(\\w+(?:(:)|(?=\\])))", + "beginCaptures": { + "1": { + "name": "support.function.any-method.objc" + }, + "2": { + "name": "punctuation.separator.arguments.objc" + } + }, + "end": "(?=\\])", + "name": "meta.function-call.objc", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objc" + } + }, + "match": "\\b\\w+(:)", + "name": "support.function.any-method.name-of-parameter.objc" + }, + { + "include": "#special_variables" + }, + { + "include": "#c_functions" + }, + { + "include": "$base" + } + ] + }, + { + "include": "#special_variables" + }, + { + "include": "#c_functions" + }, + { + "include": "$self" + } + ] + }, + "c_functions": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.whitespace.support.function.leading.c" + }, + "2": { + "name": "support.function.C99.c" + } + }, + "match": + "(\\s*)\\b(hypot(f|l)?|s(scanf|ystem|nprintf|ca(nf|lb(n(f|l)?|ln(f|l)?))|i(n(h(f|l)?|f|l)?|gn(al|bit))|tr(s(tr|pn)|nc(py|at|mp)|c(spn|hr|oll|py|at|mp)|to(imax|d|u(l(l)?|max)|k|f|l(d|l)?)|error|pbrk|ftime|len|rchr|xfrm)|printf|et(jmp|vbuf|locale|buf)|qrt(f|l)?|w(scanf|printf)|rand)|n(e(arbyint(f|l)?|xt(toward(f|l)?|after(f|l)?))|an(f|l)?)|c(s(in(h(f|l)?|f|l)?|qrt(f|l)?)|cos(h(f)?|f|l)?|imag(f|l)?|t(ime|an(h(f|l)?|f|l)?)|o(s(h(f|l)?|f|l)?|nj(f|l)?|pysign(f|l)?)|p(ow(f|l)?|roj(f|l)?)|e(il(f|l)?|xp(f|l)?)|l(o(ck|g(f|l)?)|earerr)|a(sin(h(f|l)?|f|l)?|cos(h(f|l)?|f|l)?|tan(h(f|l)?|f|l)?|lloc|rg(f|l)?|bs(f|l)?)|real(f|l)?|brt(f|l)?)|t(ime|o(upper|lower)|an(h(f|l)?|f|l)?|runc(f|l)?|gamma(f|l)?|mp(nam|file))|i(s(space|n(ormal|an)|cntrl|inf|digit|u(nordered|pper)|p(unct|rint)|finite|w(space|c(ntrl|type)|digit|upper|p(unct|rint)|lower|al(num|pha)|graph|xdigit|blank)|l(ower|ess(equal|greater)?)|al(num|pha)|gr(eater(equal)?|aph)|xdigit|blank)|logb(f|l)?|max(div|abs))|di(v|fftime)|_Exit|unget(c|wc)|p(ow(f|l)?|ut(s|c(har)?|wc(har)?)|error|rintf)|e(rf(c(f|l)?|f|l)?|x(it|p(2(f|l)?|f|l|m1(f|l)?)?))|v(s(scanf|nprintf|canf|printf|w(scanf|printf))|printf|f(scanf|printf|w(scanf|printf))|w(scanf|printf)|a_(start|copy|end|arg))|qsort|f(s(canf|e(tpos|ek))|close|tell|open|dim(f|l)?|p(classify|ut(s|c|w(s|c))|rintf)|e(holdexcept|set(e(nv|xceptflag)|round)|clearexcept|testexcept|of|updateenv|r(aiseexcept|ror)|get(e(nv|xceptflag)|round))|flush|w(scanf|ide|printf|rite)|loor(f|l)?|abs(f|l)?|get(s|c|pos|w(s|c))|re(open|e|ad|xp(f|l)?)|m(in(f|l)?|od(f|l)?|a(f|l|x(f|l)?)?))|l(d(iv|exp(f|l)?)|o(ngjmp|cal(time|econv)|g(1(p(f|l)?|0(f|l)?)|2(f|l)?|f|l|b(f|l)?)?)|abs|l(div|abs|r(int(f|l)?|ound(f|l)?))|r(int(f|l)?|ound(f|l)?)|gamma(f|l)?)|w(scanf|c(s(s(tr|pn)|nc(py|at|mp)|c(spn|hr|oll|py|at|mp)|to(imax|d|u(l(l)?|max)|k|f|l(d|l)?|mbs)|pbrk|ftime|len|r(chr|tombs)|xfrm)|to(b|mb)|rtomb)|printf|mem(set|c(hr|py|mp)|move))|a(s(sert|ctime|in(h(f|l)?|f|l)?)|cos(h(f|l)?|f|l)?|t(o(i|f|l(l)?)|exit|an(h(f|l)?|2(f|l)?|f|l)?)|b(s|ort))|g(et(s|c(har)?|env|wc(har)?)|mtime)|r(int(f|l)?|ound(f|l)?|e(name|alloc|wind|m(ove|quo(f|l)?|ainder(f|l)?))|a(nd|ise))|b(search|towc)|m(odf(f|l)?|em(set|c(hr|py|mp)|move)|ktime|alloc|b(s(init|towcs|rtowcs)|towc|len|r(towc|len))))\\b" + }, + { + "captures": { + "1": { + "name": "punctuation.whitespace.function-call.leading.c" + }, + "2": { + "name": "support.function.any-method.c" + }, + "3": { + "name": "punctuation.definition.parameters.c" + } + }, + "match": + "(?x) (?: (?= \\s ) (?:(?<=else|new|return) | (?<!\\w)) (\\s+))?\n \t\t\t(\\b \n \t\t\t\t(?!(while|for|do|if|else|switch|catch|enumerate|return|r?iterate)\\s*\\()(?:(?!NS)[A-Za-z_][A-Za-z0-9_]*+\\b | :: )++ # actual name\n \t\t\t)\n \t\t\t \\s*(\\()", + "name": "meta.function-call.c" + } + ] + }, + "comment": { + "patterns": [ + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.objc" + } + }, + "end": "\\*/", + "name": "comment.block.objc" + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.objc" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.objc" + } + }, + "end": "\\n", + "name": "comment.line.double-slash.objc", + "patterns": [ + { + "match": "(?>\\\\\\s*\\n)", + "name": "punctuation.separator.continuation.objc" + } + ] + } + ] + } + ] + }, + "disabled": { + "begin": "^\\s*#\\s*if(n?def)?\\b.*$", + "comment": "eat nested preprocessor if(def)s", + "end": "^\\s*#\\s*endif\\b.*$", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + "implementation_innards": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled-implementation" + }, + { + "include": "#preprocessor-rule-disabled-implementation" + }, + { + "include": "#preprocessor-rule-other-implementation" + }, + { + "include": "#property_directive" + }, + { + "include": "#special_variables" + }, + { + "include": "#method_super" + }, + { + "include": "$base" + } + ] + }, + "interface_innards": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled-interface" + }, + { + "include": "#preprocessor-rule-disabled-interface" + }, + { + "include": "#preprocessor-rule-other-interface" + }, + { + "include": "#properties" + }, + { + "include": "#protocol_list" + }, + { + "include": "#method" + }, + { + "include": "$base" + } + ] + }, + "method": { + "begin": "^(-|\\+)\\s*", + "end": "(?=\\{|#)|;", + "name": "meta.function.objc", + "patterns": [ + { + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.type.begin.objc" + } + }, + "end": "(\\))\\s*(\\w+\\b)", + "endCaptures": { + "1": { + "name": "punctuation.definition.type.end.objc" + }, + "2": { + "name": "entity.name.function.objc" + } + }, + "name": "meta.return-type.objc", + "patterns": [ + { + "include": "#protocol_list" + }, + { + "include": "#protocol_type_qualifier" + }, + { + "include": "$base" + } + ] + }, + { + "match": "\\b\\w+(?=:)", + "name": "entity.name.function.name-of-parameter.objc" + }, + { + "begin": "((:))\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.name-of-parameter.objc" + }, + "2": { + "name": "punctuation.separator.arguments.objc" + }, + "3": { + "name": "punctuation.definition.type.begin.objc" + } + }, + "end": "(\\))\\s*(\\w+\\b)?", + "endCaptures": { + "1": { + "name": "punctuation.definition.type.end.objc" + }, + "2": { + "name": "variable.parameter.function.objc" + } + }, + "name": "meta.argument-type.objc", + "patterns": [ + { + "include": "#protocol_list" + }, + { + "include": "#protocol_type_qualifier" + }, + { + "include": "$base" + } + ] + }, + { + "include": "#comment" + } + ] + }, + "method_super": { + "begin": "^(?=-|\\+)", + "end": "(?<=\\})|(?=#)", + "name": "meta.function-with-body.objc", + "patterns": [ + { + "include": "#method" + }, + { + "include": "$base" + } + ] + }, + "pragma-mark": { + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.pragma.c" + }, + "3": { + "name": "meta.toc-list.pragma-mark.c" + } + }, + "match": "^\\s*(#\\s*(pragma\\s+mark)\\s+(.*))", + "name": "meta.section" + }, + "preprocessor-rule-disabled-implementation": { + "begin": "^\\s*(#(if)\\s+(0)\\b).*", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.if.c" + }, + "3": { + "name": "constant.numeric.preprocessor.c" + } + }, + "end": "^\\s*(#\\s*(endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "begin": "^\\s*(#\\s*(else)\\b)", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.else.c" + } + }, + "end": "(?=^\\s*#\\s*endif\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#interface_innards" + } + ] + }, + { + "begin": "", + "end": "(?=^\\s*#\\s*(else|endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "name": "comment.block.preprocessor.if-branch.c", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + } + ] + }, + "preprocessor-rule-disabled-interface": { + "begin": "^\\s*(#(if)\\s+(0)\\b).*", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.if.c" + }, + "3": { + "name": "constant.numeric.preprocessor.c" + } + }, + "end": "^\\s*(#\\s*(endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "begin": "^\\s*(#\\s*(else)\\b)", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.else.c" + } + }, + "end": "(?=^\\s*#\\s*endif\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#interface_innards" + } + ] + }, + { + "begin": "", + "end": "(?=^\\s*#\\s*(else|endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "name": "comment.block.preprocessor.if-branch.c", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + } + ] + }, + "preprocessor-rule-enabled-implementation": { + "begin": "^\\s*(#(if)\\s+(0*1)\\b)", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.if.c" + }, + "3": { + "name": "constant.numeric.preprocessor.c" + } + }, + "end": "^\\s*(#\\s*(endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "begin": "^\\s*(#\\s*(else)\\b).*", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.else.c" + } + }, + "contentName": "comment.block.preprocessor.else-branch.c", + "end": "(?=^\\s*#\\s*endif\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + { + "begin": "", + "end": "(?=^\\s*#\\s*(else|endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#implementation_innards" + } + ] + } + ] + }, + "preprocessor-rule-enabled-interface": { + "begin": "^\\s*(#(if)\\s+(0*1)\\b)", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.if.c" + }, + "3": { + "name": "constant.numeric.preprocessor.c" + } + }, + "end": "^\\s*(#\\s*(endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "begin": "^\\s*(#\\s*(else)\\b).*", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.else.c" + } + }, + "contentName": "comment.block.preprocessor.else-branch.c", + "end": "(?=^\\s*#\\s*endif\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + { + "begin": "", + "end": "(?=^\\s*#\\s*(else|endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#interface_innards" + } + ] + } + ] + }, + "preprocessor-rule-other-implementation": { + "begin": "^\\s*(#\\s*(if(n?def)?)\\b.*?(?:(?=(?://|/\\*))|$))", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.c" + } + }, + "end": "^\\s*(#\\s*(endif)\\b).*?(?:(?=(?://|/\\*))|$)", + "patterns": [ + { + "include": "#implementation_innards" + } + ] + }, + "preprocessor-rule-other-interface": { + "begin": "^\\s*(#\\s*(if(n?def)?)\\b.*?(?:(?=(?://|/\\*))|$))", + "captures": { + "1": { + "name": "meta.preprocessor.c" + }, + "2": { + "name": "keyword.control.import.c" + } + }, + "end": "^\\s*(#\\s*(endif)\\b).*?(?:(?=(?://|/\\*))|$)", + "patterns": [ + { + "include": "#interface_innards" + } + ] + }, + "properties": { + "patterns": [ + { + "begin": "((@)property)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.other.property.objc" + }, + "2": { + "name": "punctuation.definition.keyword.objc" + }, + "3": { + "name": "punctuation.section.scope.begin.objc" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.scope.end.objc" + } + }, + "name": "meta.property-with-attributes.objc", + "patterns": [ + { + "match": + "\\b(getter|setter|readonly|readwrite|assign|retain|copy|nonatomic|strong|weak)\\b", + "name": "keyword.other.property.attribute" + } + ] + }, + { + "captures": { + "1": { + "name": "keyword.other.property.objc" + }, + "2": { + "name": "punctuation.definition.keyword.objc" + } + }, + "match": "((@)property)\\b", + "name": "meta.property.objc" + } + ] + }, + "property_directive": { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objc" + } + }, + "match": "(@)(dynamic|synthesize)\\b", + "name": "keyword.other.property.directive.objc" + }, + "protocol_list": { + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.section.scope.begin.objc" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.section.scope.end.objc" + } + }, + "name": "meta.protocol-list.objc", + "patterns": [ + { + "match": + "\\bNS(GlyphStorage|M(utableCopying|enuItem)|C(hangeSpelling|o(ding|pying|lorPicking(Custom|Default)))|T(oolbarItemValidations|ext(Input|AttachmentCell))|I(nputServ(iceProvider|erMouseTracker)|gnoreMisspelledWords)|Obj(CTypeSerializationCallBack|ect)|D(ecimalNumberBehaviors|raggingInfo)|U(serInterfaceValidations|RL(HandleClient|DownloadDelegate|ProtocolClient|AuthenticationChallengeSender))|Validated(ToobarItem|UserInterfaceItem)|Locking)\\b", + "name": "support.other.protocol.objc" + } + ] + }, + "protocol_type_qualifier": { + "match": "\\b(in|out|inout|oneway|bycopy|byref)\\b", + "name": "storage.modifier.protocol.objc" + }, + "special_variables": { + "patterns": [ + { + "match": "\\b_cmd\\b", + "name": "variable.other.selector.objc" + }, + { + "match": "\\b(self|super)\\b", + "name": "variable.language.objc" + } + ] + } + } +} diff --git a/extensions/php/syntaxes/html.tmLanguage.json b/extensions/php/syntaxes/html.tmLanguage.json new file mode 100755 index 0000000000..42d9ed082b --- /dev/null +++ b/extensions/php/syntaxes/html.tmLanguage.json @@ -0,0 +1,89 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-php/blob/master/grammars/html.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-php/commit/29c140e1531e0b5e842e5bfd4377f879d8b79cd4", + "name": "PHP", + "scopeName": "text.html.php", + "injections": { + "text.html.php - (meta.embedded | meta.tag), L:text.html.php meta.tag, L:text.html.php source.js": { + "patterns": [ + { + "include": "#php-tag" + } + ] + } + }, + "patterns": [ + { + "begin": "\\A#!", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "end": "$", + "name": "comment.line.shebang.php" + }, + { + "include": "text.html.basic" + } + ], + "repository": { + "php-tag": { + "patterns": [ + { + "begin": "<\\?(?i:php|=)?(?![^?]*\\?>)", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + } + }, + "end": "(\\?)>", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "source.php" + } + }, + "name": "meta.embedded.block.php", + "contentName": "source.php", + "patterns": [ + { + "include": "source.php" + } + ] + }, + { + "begin": "<\\?(?i:php|=)?", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + } + }, + "end": "(\\?)>", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "source.php" + } + }, + "name": "meta.embedded.line.php", + "contentName": "source.php", + "patterns": [ + { + "include": "source.php" + } + ] + } + ] + } + } +} diff --git a/extensions/php/syntaxes/php.tmLanguage.json b/extensions/php/syntaxes/php.tmLanguage.json new file mode 100755 index 0000000000..869703ae68 --- /dev/null +++ b/extensions/php/syntaxes/php.tmLanguage.json @@ -0,0 +1,3569 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-php/blob/master/grammars/php.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-php/commit/b054176835218c446d22b3c1b9dcfdcf8cacf49f", + "scopeName": "source.php", + "patterns": [ + { + "include": "#comments" + }, + { + "begin": + "(?i)^\\s*(interface)\\s+([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)\\s*(extends)?\\s*", + "beginCaptures": { + "1": { + "name": "storage.type.interface.php" + }, + "2": { + "name": "entity.name.type.interface.php" + }, + "3": { + "name": "storage.modifier.extends.php" + } + }, + "end": + "(?i)((?:[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*\\s*,\\s*)*)([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)?\\s*(?:(?={)|$)", + "endCaptures": { + "1": { + "patterns": [ + { + "match": + "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "entity.other.inherited-class.php" + }, + { + "match": ",", + "name": "punctuation.separator.classes.php" + } + ] + }, + "2": { + "name": "entity.other.inherited-class.php" + } + }, + "name": "meta.interface.php", + "patterns": [ + { + "include": "#namespace" + } + ] + }, + { + "begin": + "(?i)^\\s*(trait)\\s+([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)", + "beginCaptures": { + "1": { + "name": "storage.type.trait.php" + }, + "2": { + "name": "entity.name.type.trait.php" + } + }, + "end": "(?={)", + "name": "meta.trait.php", + "patterns": [ + { + "include": "#comments" + } + ] + }, + { + "match": + "(?i)(?:^|(?<=<\\?php))\\s*(namespace)\\s+([a-z0-9_\\x{7f}-\\x{7fffffff}\\\\]+)(?=\\s*;)", + "name": "meta.namespace.php", + "captures": { + "1": { + "name": "keyword.other.namespace.php" + }, + "2": { + "name": "entity.name.type.namespace.php", + "patterns": [ + { + "match": "\\\\", + "name": "punctuation.separator.inheritance.php" + } + ] + } + } + }, + { + "begin": "(?i)(?:^|(?<=<\\?php))\\s*(namespace)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.other.namespace.php" + } + }, + "end": "(?<=})|(?=\\?>)", + "name": "meta.namespace.php", + "patterns": [ + { + "include": "#comments" + }, + { + "match": "(?i)[a-z0-9_\\x{7f}-\\x{7fffffff}\\\\]+", + "name": "entity.name.type.namespace.php", + "captures": { + "0": { + "patterns": [ + { + "match": "\\\\", + "name": "punctuation.separator.inheritance.php" + } + ] + } + } + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.namespace.begin.bracket.curly.php" + } + }, + "end": "}|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.namespace.end.bracket.curly.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "match": "[^\\s]+", + "name": "invalid.illegal.identifier.php" + } + ] + }, + { + "match": "\\s+(?=use\\b)" + }, + { + "begin": "(?i)\\buse\\b", + "beginCaptures": { + "0": { + "name": "keyword.other.use.php" + } + }, + "end": "(?<=})|(?=;)", + "name": "meta.use.php", + "patterns": [ + { + "match": "\\b(const|function)\\b", + "name": "storage.type.${1:/downcase}.php" + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.use.begin.bracket.curly.php" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.definition.use.end.bracket.curly.php" + } + }, + "patterns": [ + { + "include": "#scope-resolution" + }, + { + "match": + "(?xi)\n\\b(as)\n\\s+(final|abstract|public|private|protected|static)\n\\s+([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)", + "captures": { + "1": { + "name": "keyword.other.use-as.php" + }, + "2": { + "name": "storage.modifier.php" + }, + "3": { + "name": "entity.other.alias.php" + } + } + }, + { + "match": + "(?xi)\n\\b(as)\n\\s+([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)", + "captures": { + "1": { + "name": "keyword.other.use-as.php" + }, + "2": { + "patterns": [ + { + "match": + "^(?:final|abstract|public|private|protected|static)$", + "name": "storage.modifier.php" + }, + { + "match": ".+", + "name": "entity.other.alias.php" + } + ] + } + } + }, + { + "match": + "(?i)\\b(insteadof)\\s+([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)", + "captures": { + "1": { + "name": "keyword.other.use-insteadof.php" + }, + "2": { + "name": "support.class.php" + } + } + }, + { + "match": ";", + "name": "punctuation.terminator.expression.php" + }, + { + "include": "#use-inner" + } + ] + }, + { + "include": "#use-inner" + } + ] + }, + { + "begin": + "(?i)(?:^|(?<=}))\\s*(?:(abstract|final)\\s+)?(class)\\s+([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)", + "beginCaptures": { + "1": { + "name": "storage.modifier.${1:/downcase}.php" + }, + "2": { + "name": "storage.type.class.php" + }, + "3": { + "name": "entity.name.type.class.php" + } + }, + "end": "}|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.class.end.bracket.curly.php" + } + }, + "name": "meta.class.php", + "patterns": [ + { + "include": "#comments" + }, + { + "begin": "(?i)(extends)\\s+", + "beginCaptures": { + "1": { + "name": "storage.modifier.extends.php" + } + }, + "contentName": "meta.other.inherited-class.php", + "end": "(?i)(?=[^a-z0-9_\\x{7f}-\\x{7fffffff}\\\\])", + "patterns": [ + { + "begin": + "(?i)(?=\\\\?[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*\\\\)", + "end": + "(?i)([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)?(?=[^a-z0-9_\\x{7f}-\\x{7fffffff}\\\\])", + "endCaptures": { + "1": { + "name": "entity.other.inherited-class.php" + } + }, + "patterns": [ + { + "include": "#namespace" + } + ] + }, + { + "include": "#class-builtin" + }, + { + "include": "#namespace" + }, + { + "match": + "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "entity.other.inherited-class.php" + } + ] + }, + { + "begin": "(?i)(implements)\\s+", + "beginCaptures": { + "1": { + "name": "storage.modifier.implements.php" + } + }, + "end": "(?i)(?=[;{])", + "patterns": [ + { + "include": "#comments" + }, + { + "begin": "(?i)(?=[a-z0-9_\\x{7f}-\\x{7fffffff}\\\\]+)", + "contentName": "meta.other.inherited-class.php", + "end": + "(?i)(?:\\s*(?:,|(?=[^a-z0-9_\\x{7f}-\\x{7fffffff}\\\\\\s]))\\s*)", + "patterns": [ + { + "begin": + "(?i)(?=\\\\?[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*\\\\)", + "end": + "(?i)([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)?(?=[^a-z0-9_\\x{7f}-\\x{7fffffff}\\\\])", + "endCaptures": { + "1": { + "name": "entity.other.inherited-class.php" + } + }, + "patterns": [ + { + "include": "#namespace" + } + ] + }, + { + "include": "#class-builtin" + }, + { + "include": "#namespace" + }, + { + "match": + "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "entity.other.inherited-class.php" + } + ] + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.class.begin.bracket.curly.php" + } + }, + "end": "(?=}|\\?>)", + "contentName": "meta.class.body.php", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + { + "include": "#switch_statement" + }, + { + "match": "\\s*\\b(yield\\s+from)\\b", + "captures": { + "1": { + "name": "keyword.control.yield-from.php" + } + } + }, + { + "match": + "(?x)\n\\s* # FIXME: Removing this causes specs to fail. Investigate.\n\\b(\n break|case|continue|declare|default|die|do|\n else(if)?|end(declare|for(each)?|if|switch|while)|exit|\n for(each)?|if|return|switch|use|while|yield\n)\\b", + "captures": { + "1": { + "name": "keyword.control.${1:/downcase}.php" + } + } + }, + { + "begin": "(?i)\\b((?:require|include)(?:_once)?)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.control.import.include.php" + } + }, + "end": "(?=\\s|;|$|\\?>)", + "name": "meta.include.php", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "\\b(catch)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.control.exception.catch.php" + }, + "2": { + "name": "punctuation.definition.parameters.begin.bracket.round.php" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.php" + } + }, + "name": "meta.catch.php", + "patterns": [ + { + "include": "#namespace" + }, + { + "match": + "(?xi)\n([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Exception class\n((?:\\s*\\|\\s*[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)*) # Optional additional exception classes\n\\s*\n((\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Variable", + "captures": { + "1": { + "name": "support.class.exception.php" + }, + "2": { + "patterns": [ + { + "match": + "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "support.class.exception.php" + }, + { + "match": "\\|", + "name": "punctuation.separator.delimiter.php" + } + ] + }, + "3": { + "name": "variable.other.php" + }, + "4": { + "name": "punctuation.definition.variable.php" + } + } + } + ] + }, + { + "match": "\\b(catch|try|throw|exception|finally)\\b", + "name": "keyword.control.exception.php" + }, + { + "begin": "(?i)\\b(function)\\s*(?=\\()", + "beginCaptures": { + "1": { + "name": "storage.type.function.php" + } + }, + "end": "(?={)", + "name": "meta.function.closure.php", + "patterns": [ + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.bracket.round.php" + } + }, + "contentName": "meta.function.parameters.php", + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.php" + } + }, + "patterns": [ + { + "include": "#function-parameters" + } + ] + }, + { + "begin": "(?i)(use)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.other.function.use.php" + }, + "2": { + "name": "punctuation.definition.parameters.begin.bracket.round.php" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.php" + } + }, + "patterns": [ + { + "captures": { + "1": { + "name": "variable.other.php" + }, + "2": { + "name": "storage.modifier.reference.php" + }, + "3": { + "name": "punctuation.definition.variable.php" + } + }, + "match": + "(?i)((&)?\\s*(\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)\\s*(?=,|\\))", + "name": "meta.function.closure.use.php" + } + ] + } + ] + }, + { + "begin": + "(?x)\n((?:(?:final|abstract|public|private|protected|static)\\s+)*)\n(function)\\s+\n(?i:\n (__(?:call|construct|debugInfo|destruct|get|set|isset|unset|toString|\n clone|set_state|sleep|wakeup|autoload|invoke|callStatic))\n |([a-zA-Z_\\x{7f}-\\x{7fffffff}][a-zA-Z0-9_\\x{7f}-\\x{7fffffff}]*)\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "match": "final|abstract|public|private|protected|static", + "name": "storage.modifier.php" + } + ] + }, + "2": { + "name": "storage.type.function.php" + }, + "3": { + "name": "support.function.magic.php" + }, + "4": { + "name": "entity.name.function.php" + }, + "5": { + "name": "punctuation.definition.parameters.begin.bracket.round.php" + } + }, + "contentName": "meta.function.parameters.php", + "end": + "(\\))(?:\\s*(:)\\s*(\\?)?\\s*([a-zA-Z_\\x{7f}-\\x{7fffffff}][a-zA-Z0-9_\\x{7f}-\\x{7fffffff}]*))?", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.bracket.round.php" + }, + "2": { + "name": "keyword.operator.return-value.php" + }, + "3": { + "name": "keyword.operator.nullable-type.php" + }, + "4": { + "name": "storage.type.php" + } + }, + "name": "meta.function.php", + "patterns": [ + { + "include": "#function-parameters" + } + ] + }, + { + "include": "#invoke-call" + }, + { + "include": "#scope-resolution" + }, + { + "include": "#variables" + }, + { + "include": "#strings" + }, + { + "captures": { + "1": { + "name": "support.function.construct.php" + }, + "2": { + "name": "punctuation.definition.array.begin.bracket.round.php" + }, + "3": { + "name": "punctuation.definition.array.end.bracket.round.php" + } + }, + "match": "(array)(\\()(\\))", + "name": "meta.array.empty.php" + }, + { + "begin": "(array)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "support.function.construct.php" + }, + "2": { + "name": "punctuation.definition.array.begin.bracket.round.php" + } + }, + "end": "\\)|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.bracket.round.php" + } + }, + "name": "meta.array.php", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "match": + "(?i)(\\()\\s*(array|real|double|float|int(?:eger)?|bool(?:ean)?|string|object|binary|unset)\\s*(\\))", + "captures": { + "1": { + "name": "punctuation.definition.storage-type.begin.bracket.round.php" + }, + "2": { + "name": "storage.type.php" + }, + "3": { + "name": "punctuation.definition.storage-type.end.bracket.round.php" + } + } + }, + { + "match": + "(?i)\\b(array|real|double|float|int(eger)?|bool(ean)?|string|class|var|function|interface|trait|parent|self|object)\\b", + "name": "storage.type.php" + }, + { + "match": + "(?i)\\b(global|abstract|const|extends|implements|final|private|protected|public|static)\\b", + "name": "storage.modifier.php" + }, + { + "include": "#object" + }, + { + "match": ";", + "name": "punctuation.terminator.expression.php" + }, + { + "match": ":", + "name": "punctuation.terminator.statement.php" + }, + { + "include": "#heredoc" + }, + { + "include": "#numbers" + }, + { + "match": "(?i)\\bclone\\b", + "name": "keyword.other.clone.php" + }, + { + "match": "\\.=?", + "name": "keyword.operator.string.php" + }, + { + "match": "=>", + "name": "keyword.operator.key.php" + }, + { + "captures": { + "1": { + "name": "keyword.operator.assignment.php" + }, + "2": { + "name": "storage.modifier.reference.php" + }, + "3": { + "name": "storage.modifier.reference.php" + } + }, + "match": "(?i)(\\=)(&)|(&)(?=[$a-z_])" + }, + { + "match": "@", + "name": "keyword.operator.error-control.php" + }, + { + "match": "===|==|!==|!=|<>", + "name": "keyword.operator.comparison.php" + }, + { + "match": "=|\\+=|\\-=|\\*=|/=|%=|&=|\\|=|\\^=|<<=|>>=", + "name": "keyword.operator.assignment.php" + }, + { + "match": "<=>|<=|>=|<|>", + "name": "keyword.operator.comparison.php" + }, + { + "match": "\\-\\-|\\+\\+", + "name": "keyword.operator.increment-decrement.php" + }, + { + "match": "\\-|\\+|\\*|/|%", + "name": "keyword.operator.arithmetic.php" + }, + { + "match": "(?i)(!|&&|\\|\\|)|\\b(and|or|xor|as)\\b", + "name": "keyword.operator.logical.php" + }, + { + "include": "#function-call" + }, + { + "match": "<<|>>|~|\\^|&|\\|", + "name": "keyword.operator.bitwise.php" + }, + { + "begin": "(?i)\\b(instanceof)\\s+(?=[\\\\$a-z_])", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.php" + } + }, + "end": "(?=[^\\\\$a-z0-9_\\x{7f}-\\x{7fffffff}])", + "patterns": [ + { + "include": "#class-name" + }, + { + "include": "#variable-name" + } + ] + }, + { + "include": "#instantiation" + }, + { + "captures": { + "1": { + "name": "keyword.control.goto.php" + }, + "2": { + "name": "support.other.php" + } + }, + "match": "(?i)(goto)\\s+([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)" + }, + { + "captures": { + "1": { + "name": "entity.name.goto-label.php" + } + }, + "match": + "(?i)^\\s*([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)\\s*:(?!:)" + }, + { + "include": "#string-backtick" + }, + { + "include": "#ternary_shorthand" + }, + { + "include": "#null_coalescing" + }, + { + "include": "#ternary_expression" + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.begin.bracket.curly.php" + } + }, + "end": "}|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.end.bracket.curly.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.array.begin.php" + } + }, + "end": "\\]|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.section.array.end.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.begin.bracket.round.php" + } + }, + "end": "\\)|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.end.bracket.round.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "include": "#constants" + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.php" + } + ], + "repository": { + "class-builtin": { + "patterns": [ + { + "match": + "(?xi)\n(\\\\)?\\b\n((APC|Append)Iterator|Array(Access|Iterator|Object)\n|Bad(Function|Method)CallException\n|(Caching|CallbackFilter)Iterator|Collator|Collectable|Cond|Countable|CURLFile\n|Date(Interval|Period|Time(Interface|Immutable|Zone)?)?|Directory(Iterator)?|DomainException\n|DOM(Attr|CdataSection|CharacterData|Comment|Document(Fragment)?|Element|EntityReference\n |Implementation|NamedNodeMap|Node(list)?|ProcessingInstruction|Text|XPath)\n|(Error)?Exception|EmptyIterator\n|finfo\n|Ev(Check|Child|Embed|Fork|Idle|Io|Loop|Periodic|Prepare|Signal|Stat|Timer|Watcher)?\n|Event(Base|Buffer(Event)?|SslContext|Http(Request|Connection)?|Config|DnsBase|Util|Listener)?\n|FANNConnection|(Filter|Filesystem)Iterator\n|Gender\\\\Gender|GlobIterator|Gmagick(Draw|Pixel)?\n|Haru(Annotation|Destination|Doc|Encoder|Font|Image|Outline|Page)\n|Http((Inflate|Deflate)?Stream|Message|Request(Pool)?|Response|QueryString)\n|HRTime\\\\(PerformanceCounter|StopWatch)\n|Intl(Calendar|((CodePoint|RuleBased)?Break|Parts)?Iterator|DateFormatter|TimeZone)\n|Imagick(Draw|Pixel(Iterator)?)?\n|InfiniteIterator|InvalidArgumentException|Iterator(Aggregate|Iterator)?\n|JsonSerializable\n|KTaglib_(MPEG_(File|AudioProperties)|Tag|ID3v2_(Tag|(AttachedPicture)?Frame))\n|Lapack|(Length|Locale|Logic)Exception|LimitIterator|Lua(Closure)?\n|Mongo(BinData|Client|Code|Collection|CommandCursor|Cursor(Exception)?|Date|DB(Ref)?|DeleteBatch\n |Grid(FS(Cursor|File)?)|Id|InsertBatch|Int(32|64)|Log|Pool|Regex|ResultException|Timestamp\n |UpdateBatch|Write(Batch|ConcernException))?\n|Memcache(d)?|MessageFormatter|MultipleIterator|Mutex\n|mysqli(_(driver|stmt|warning|result))?\n|MysqlndUh(Connection|PreparedStatement)\n|NoRewindIterator|Normalizer|NumberFormatter\n|OCI-(Collection|Lob)|OuterIterator|(OutOf(Bounds|Range)|Overflow)Exception\n|ParentIterator|PDO(Statement)?|Phar(Data|FileInfo)?|php_user_filter|Pool\n|QuickHash(Int(Set|StringHash)|StringIntHash)\n|Recursive(Array|Caching|Directory|Fallback|Filter|Iterator|Regex|Tree)?Iterator\n|Reflection(Class|Function(Abstract)?|Method|Object|Parameter|Property|(Zend)?Extension)?\n|RangeException|Reflector|RegexIterator|ResourceBundle|RuntimeException|RRD(Creator|Graph|Updater)\n|SAM(Connection|Message)|SCA(_(SoapProxy|LocalProxy))?\n|SDO_(DAS_(ChangeSummary|Data(Factory|Object)|Relational|Setting|XML(_Document)?)\n |Data(Factory|Object)|Exception|List|Model_(Property|ReflectionDataObject|Type)|Sequence)\n|SeekableIterator|Serializable|SessionHandler(Interface)?|SimpleXML(Iterator|Element)|SNMP\n|Soap(Client|Fault|Header|Param|Server|Var)\n|SphinxClient|Spoofchecker\n|Spl(DoublyLinkedList|Enum|File(Info|Object)|FixedArray|(Max|Min)?Heap|Observer|ObjectStorage\n |(Priority)?Queue|Stack|Subject|Type|TempFileObject)\n|SQLite(3(Result|Stmt)?|Database|Result|Unbuffered)\n|stdClass|streamWrapper|SVM(Model)?|Swish(Result(s)?|Search)?|Sync(Event|Mutex|ReaderWriter|Semaphore)\n|Thread(ed)?|tidy(Node)?|TokyoTyrant(Table|Iterator|Query)?|Transliterator|Traversable\n|UConverter|(Underflow|UnexpectedValue)Exception\n|V8Js(Exception)?|Varnish(Admin|Log|Stat)\n|Worker|Weak(Map|Ref)\n|XML(Diff\\\\(Base|DOM|File|Memory)|Reader|Writer)|XsltProcessor\n|Yaf_(Route_(Interface|Map|Regex|Rewrite|Simple|Supervar)\n |Action_Abstract|Application|Config_(Simple|Ini|Abstract)|Controller_Abstract\n |Dispatcher|Exception|Loader|Plugin_Abstract|Registry|Request_(Abstract|Simple|Http)\n |Response_Abstract|Router|Session|View_(Simple|Interface))\n|Yar_(Client(_Exception)?|Concurrent_Client|Server(_Exception)?)\n|ZipArchive|ZMQ(Context|Device|Poll|Socket)?)\n\\b", + "name": "support.class.builtin.php", + "captures": { + "1": { + "name": "punctuation.separator.inheritance.php" + } + } + } + ] + }, + "class-name": { + "patterns": [ + { + "begin": "(?i)(?=\\\\?[a-z_0-9]+\\\\)", + "end": "(?i)([a-z_][a-z_0-9]*)?(?![a-z0-9_\\\\])", + "endCaptures": { + "1": { + "name": "support.class.php" + } + }, + "patterns": [ + { + "include": "#namespace" + } + ] + }, + { + "include": "#class-builtin" + }, + { + "begin": "(?=[\\\\a-zA-Z_])", + "end": "(?i)([a-z_][a-z_0-9]*)?(?![a-z0-9_\\\\])", + "endCaptures": { + "1": { + "name": "support.class.php" + } + }, + "patterns": [ + { + "include": "#namespace" + } + ] + } + ] + }, + "comments": { + "patterns": [ + { + "begin": "/\\*\\*(?=\\s)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "name": "comment.block.documentation.phpdoc.php", + "patterns": [ + { + "include": "#php_doc" + } + ] + }, + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "end": "\\*/", + "name": "comment.block.php" + }, + { + "begin": "(^\\s+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.php" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "end": "\\n|(?=\\?>)", + "name": "comment.line.double-slash.php" + } + ] + }, + { + "begin": "(^\\s+)?(?=#)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.php" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "#", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "end": "\\n|(?=\\?>)", + "name": "comment.line.number-sign.php" + } + ] + } + ] + }, + "constants": { + "patterns": [ + { + "match": + "(?i)\\b(TRUE|FALSE|NULL|__(FILE|DIR|FUNCTION|CLASS|METHOD|LINE|NAMESPACE)__|ON|OFF|YES|NO|NL|BR|TAB)\\b", + "name": "constant.language.php" + }, + { + "match": + "(?x)\n(\\\\)?\\b\n(DEFAULT_INCLUDE_PATH\n|EAR_(INSTALL|EXTENSION)_DIR\n|E_(ALL|COMPILE_(ERROR|WARNING)|CORE_(ERROR|WARNING)|DEPRECATED|ERROR|NOTICE\n |PARSE|RECOVERABLE_ERROR|STRICT|USER_(DEPRECATED|ERROR|NOTICE|WARNING)|WARNING)\n|PHP_(ROUND_HALF_(DOWN|EVEN|ODD|UP)|(MAJOR|MINOR|RELEASE)_VERSION|MAXPATHLEN\n |BINDIR|SHLIB_SUFFIX|SYSCONFDIR|SAPI|CONFIG_FILE_(PATH|SCAN_DIR)\n |INT_(MAX|SIZE)|ZTS|OS|OUTPUT_HANDLER_(START|CONT|END)|DEBUG|DATADIR\n |URL_(SCHEME|HOST|USER|PORT|PASS|PATH|QUERY|FRAGMENT)|PREFIX\n |EXTRA_VERSION|EXTENSION_DIR|EOL|VERSION(_ID)?\n |WINDOWS_(NT_(SERVER|DOMAIN_CONTROLLER|WORKSTATION)\n |VERSION_(MAJOR|MINOR)|BUILD|SUITEMASK|SP_(MAJOR|MINOR)\n |PRODUCTTYPE|PLATFORM)\n |LIBDIR|LOCALSTATEDIR)\n|STD(ERR|IN|OUT)|ZEND_(DEBUG_BUILD|THREAD_SAFE))\n\\b", + "name": "support.constant.core.php", + "captures": { + "1": { + "name": "punctuation.separator.inheritance.php" + } + } + }, + { + "match": + "(?x)\n(\\\\)?\\b\n(__COMPILER_HALT_OFFSET__|AB(MON_(1|2|3|4|5|6|7|8|9|10|11|12)|DAY[1-7])\n|AM_STR|ASSERT_(ACTIVE|BAIL|CALLBACK_QUIET_EVAL|WARNING)|ALT_DIGITS\n|CASE_(UPPER|LOWER)|CHAR_MAX|CONNECTION_(ABORTED|NORMAL|TIMEOUT)|CODESET|COUNT_(NORMAL|RECURSIVE)\n|CREDITS_(ALL|DOCS|FULLPAGE|GENERAL|GROUP|MODULES|QA|SAPI)\n|CRYPT_(BLOWFISH|EXT_DES|MD5|SHA(256|512)|SALT_LENGTH|STD_DES)|CURRENCY_SYMBOL\n|D_(T_)?FMT|DATE_(ATOM|COOKIE|ISO8601|RFC(822|850|1036|1123|2822|3339)|RSS|W3C)\n|DAY_[1-7]|DECIMAL_POINT|DIRECTORY_SEPARATOR\n|ENT_(COMPAT|IGNORE|(NO)?QUOTES)|EXTR_(IF_EXISTS|OVERWRITE|PREFIX_(ALL|IF_EXISTS|INVALID|SAME)|REFS|SKIP)\n|ERA(_(D_(T_)?FMT)|T_FMT|YEAR)?|FRAC_DIGITS|GROUPING|HASH_HMAC|HTML_(ENTITIES|SPECIALCHARS)\n|INF|INFO_(ALL|CREDITS|CONFIGURATION|ENVIRONMENT|GENERAL|LICENSEMODULES|VARIABLES)\n|INI_(ALL|CANNER_(NORMAL|RAW)|PERDIR|SYSTEM|USER)|INT_(CURR_SYMBOL|FRAC_DIGITS)\n|LC_(ALL|COLLATE|CTYPE|MESSAGES|MONETARY|NUMERIC|TIME)|LOCK_(EX|NB|SH|UN)\n|LOG_(ALERT|AUTH(PRIV)?|CRIT|CRON|CONS|DAEMON|DEBUG|EMERG|ERR|INFO|LOCAL[1-7]|LPR|KERN|MAIL\n |NEWS|NODELAY|NOTICE|NOWAIT|ODELAY|PID|PERROR|WARNING|SYSLOG|UCP|USER)\n|M_(1_PI|SQRT(1_2|2|3|PI)|2_(SQRT)?PI|PI(_(2|4))?|E(ULER)?|LN(10|2|PI)|LOG(10|2)E)\n|MON_(1|2|3|4|5|6|7|8|9|10|11|12|DECIMAL_POINT|GROUPING|THOUSANDS_SEP)\n|N_(CS_PRECEDES|SEP_BY_SPACE|SIGN_POSN)|NAN|NEGATIVE_SIGN|NO(EXPR|STR)\n|P_(CS_PRECEDES|SEP_BY_SPACE|SIGN_POSN)|PM_STR|POSITIVE_SIGN\n|PATH(_SEPARATOR|INFO_(EXTENSION|(BASE|DIR|FILE)NAME))|RADIXCHAR\n|SEEK_(CUR|END|SET)|SORT_(ASC|DESC|LOCALE_STRING|REGULAR|STRING)|STR_PAD_(BOTH|LEFT|RIGHT)\n|T_FMT(_AMPM)?|THOUSEP|THOUSANDS_SEP\n|UPLOAD_ERR_(CANT_WRITE|EXTENSION|(FORM|INI)_SIZE|NO_(FILE|TMP_DIR)|OK|PARTIAL)\n|YES(EXPR|STR))\n\\b", + "name": "support.constant.std.php", + "captures": { + "1": { + "name": "punctuation.separator.inheritance.php" + } + } + }, + { + "match": + "(?x)\n(\\\\)?\\b\n(GLOB_(MARK|BRACE|NO(SORT|CHECK|ESCAPE)|ONLYDIR|ERR|AVAILABLE_FLAGS)\n|XML_(SAX_IMPL|(DTD|DOCUMENT(_(FRAG|TYPE))?|HTML_DOCUMENT|NOTATION|NAMESPACE_DECL|PI|COMMENT|DATA_SECTION|TEXT)_NODE\n |OPTION_(SKIP_(TAGSTART|WHITE)|CASE_FOLDING|TARGET_ENCODING)\n |ERROR_((BAD_CHAR|(ATTRIBUTE_EXTERNAL|BINARY|PARAM|RECURSIVE)_ENTITY)_REF|MISPLACED_XML_PI|SYNTAX|NONE\n |NO_(MEMORY|ELEMENTS)|TAG_MISMATCH|INCORRECT_ENCODING|INVALID_TOKEN|DUPLICATE_ATTRIBUTE\n |UNCLOSED_(CDATA_SECTION|TOKEN)|UNDEFINED_ENTITY|UNKNOWN_ENCODING|JUNK_AFTER_DOC_ELEMENT\n |PARTIAL_CHAR|EXTERNAL_ENTITY_HANDLING|ASYNC_ENTITY)\n |ENTITY_(((REF|DECL)_)?NODE)|ELEMENT(_DECL)?_NODE|LOCAL_NAMESPACE|ATTRIBUTE_(NMTOKEN(S)?|NOTATION|NODE)\n |CDATA|ID(REF(S)?)?|DECL_NODE|ENTITY|ENUMERATION)\n|MHASH_(RIPEMD(128|160|256|320)|GOST|MD(2|4|5)|SHA(1|224|256|384|512)|SNEFRU256|HAVAL(128|160|192|224|256)\n |CRC23(B)?|TIGER(128|160)?|WHIRLPOOL|ADLER32)\n|MYSQL_(BOTH|NUM|CLIENT_(SSL|COMPRESS|IGNORE_SPACE|INTERACTIVE|ASSOC))\n|MYSQLI_(REPORT_(STRICT|INDEX|OFF|ERROR|ALL)|REFRESH_(GRANT|MASTER|BACKUP_LOG|STATUS|SLAVE|HOSTS|THREADS|TABLES|LOG)\n |READ_DEFAULT_(FILE|GROUP)|(GROUP|MULTIPLE_KEY|BINARY|BLOB)_FLAG|BOTH\n |STMT_ATTR_(CURSOR_TYPE|UPDATE_MAX_LENGTH|PREFETCH_ROWS)|STORE_RESULT\n |SERVER_QUERY_(NO_((GOOD_)?INDEX_USED)|WAS_SLOW)|SET_(CHARSET_NAME|FLAG)\n |NO_(DEFAULT_VALUE_FLAG|DATA)|NOT_NULL_FLAG|NUM(_FLAG)?\n |CURSOR_TYPE_(READ_ONLY|SCROLLABLE|NO_CURSOR|FOR_UPDATE)\n |CLIENT_(SSL|NO_SCHEMA|COMPRESS|IGNORE_SPACE|INTERACTIVE|FOUND_ROWS)\n |TYPE_(GEOMETRY|((MEDIUM|LONG|TINY)_)?BLOB|BIT|SHORT|STRING|SET|YEAR|NULL|NEWDECIMAL|NEWDATE|CHAR\n |TIME(STAMP)?|TINY|INT24|INTERVAL|DOUBLE|DECIMAL|DATE(TIME)?|ENUM|VAR_STRING|FLOAT|LONG(LONG)?)\n |TIME_STAMP_FLAG|INIT_COMMAND|ZEROFILL_FLAG|ON_UPDATE_NOW_FLAG\n |OPT_(NET_((CMD|READ)_BUFFER_SIZE)|CONNECT_TIMEOUT|INT_AND_FLOAT_NATIVE|LOCAL_INFILE)\n |DEBUG_TRACE_ENABLED|DATA_TRUNCATED|USE_RESULT|(ENUM|(PART|PRI|UNIQUE)_KEY|UNSIGNED)_FLAG\n |ASSOC|ASYNC|AUTO_INCREMENT_FLAG)\n|MCRYPT_(RC(2|6)|RIJNDAEL_(128|192|256)|RAND|GOST|XTEA|MODE_(STREAM|NOFB|CBC|CFB|OFB|ECB)|MARS\n |BLOWFISH(_COMPAT)?|SERPENT|SKIPJACK|SAFER(64|128|PLUS)|CRYPT|CAST_(128|256)|TRIPLEDES|THREEWAY\n |TWOFISH|IDEA|(3)?DES|DECRYPT|DEV_(U)?RANDOM|PANAMA|ENCRYPT|ENIGNA|WAKE|LOKI97|ARCFOUR(_IV)?)\n|STREAM_(REPORT_ERRORS|MUST_SEEK|MKDIR_RECURSIVE|BUFFER_(NONE|FULL|LINE)|SHUT_(RD)?WR\n |SOCK_(RDM|RAW|STREAM|SEQPACKET|DGRAM)|SERVER_(BIND|LISTEN)\n |NOTIFY_(REDIRECTED|RESOLVE|MIME_TYPE_IS|SEVERITY_(INFO|ERR|WARN)|COMPLETED|CONNECT|PROGRESS\n |FILE_SIZE_IS|FAILURE|AUTH_(REQUIRED|RESULT))\n |CRYPTO_METHOD_((SSLv2(3)?|SSLv3|TLS)_(CLIENT|SERVER))|CLIENT_((ASYNC_)?CONNECT|PERSISTENT)\n |CAST_(AS_STREAM|FOR_SELECT)|(IGNORE|IS)_URL|IPPROTO_(RAW|TCP|ICMP|IP|UDP)|OOB\n |OPTION_(READ_(BUFFER|TIMEOUT)|BLOCKING|WRITE_BUFFER)|URL_STAT_(LINK|QUIET)|USE_PATH\n |PEEK|PF_(INET(6)?|UNIX)|ENFORCE_SAFE_MODE|FILTER_(ALL|READ|WRITE))\n|SUNFUNCS_RET_(DOUBLE|STRING|TIMESTAMP)\n|SQLITE_(READONLY|ROW|MISMATCH|MISUSE|BOTH|BUSY|SCHEMA|NOMEM|NOTFOUND|NOTADB|NOLFS|NUM|CORRUPT\n |CONSTRAINT|CANTOPEN|TOOBIG|INTERRUPT|INTERNAL|IOERR|OK|DONE|PROTOCOL|PERM|ERROR|EMPTY\n |FORMAT|FULL|LOCKED|ABORT|ASSOC|AUTH)\n|SQLITE3_(BOTH|BLOB|NUM|NULL|TEXT|INTEGER|OPEN_(READ(ONLY|WRITE)|CREATE)|FLOAT_ASSOC)\n|CURL(M_(BAD_((EASY)?HANDLE)|CALL_MULTI_PERFORM|INTERNAL_ERROR|OUT_OF_MEMORY|OK)\n |MSG_DONE|SSH_AUTH_(HOST|NONE|DEFAULT|PUBLICKEY|PASSWORD|KEYBOARD)\n |CLOSEPOLICY_(SLOWEST|CALLBACK|OLDEST|LEAST_(RECENTLY_USED|TRAFFIC)\n |INFO_(REDIRECT_(COUNT|TIME)|REQUEST_SIZE|SSL_VERIFYRESULT|STARTTRANSFER_TIME\n |(SIZE|SPEED)_(DOWNLOAD|UPLOAD)|HTTP_CODE|HEADER_(OUT|SIZE)|NAMELOOKUP_TIME\n |CONNECT_TIME|CONTENT_(TYPE|LENGTH_(DOWNLOAD|UPLOAD))|CERTINFO|TOTAL_TIME\n |PRIVATE|PRETRANSFER_TIME|EFFECTIVE_URL|FILETIME)\n |OPT_(RESUME_FROM|RETURNTRANSFER|REDIR_PROTOCOLS|REFERER|READ(DATA|FUNCTION)|RANGE|RANDOM_FILE\n |MAX(CONNECTS|REDIRS)|BINARYTRANSFER|BUFFERSIZE\n |SSH_(HOST_PUBLIC_KEY_MD5|(PRIVATE|PUBLIC)_KEYFILE)|AUTH_TYPES)\n |SSL(CERT(TYPE|PASSWD)?|ENGINE(_DEFAULT)?|VERSION|KEY(TYPE|PASSWD)?)\n |SSL_(CIPHER_LIST|VERIFY(HOST|PEER))\n |STDERR|HTTP(GET|HEADER|200ALIASES|_VERSION|PROXYTUNNEL|AUTH)\n |HEADER(FUNCTION)?|NO(BODY|SIGNAL|PROGRESS)|NETRC|CRLF|CONNECTTIMEOUT(_MS)?\n |COOKIE(SESSION|JAR|FILE)?|CUSTOMREQUEST|CERTINFO|CLOSEPOLICY|CA(INFO|PATH)|TRANSFERTEXT\n |TCP_NODELAY|TIME(CONDITION|OUT(_MS)?|VALUE)|INTERFACE|INFILE(SIZE)?|IPRESOLVE\n |DNS_(CACHE_TIMEOUT|USE_GLOBAL_CACHE)|URL|USER(AGENT|PWD)|UNRESTRICTED_AUTH|UPLOAD\n |PRIVATE|PROGRESSFUNCTION|PROXY(TYPE|USERPWD|PORT|AUTH)?|PROTOCOLS|PORT\n |POST(REDIR|QUOTE|FIELDS)?|PUT|EGDSOCKET|ENCODING|VERBOSE|KRB4LEVEL|KEYPASSWD|QUOTE|FRESH_CONNECT\n |FTP(APPEND|LISTONLY|PORT|SSLAUTH)\n |FTP_(SSL|SKIP_PASV_IP|CREATE_MISSING_DIRS|USE_EP(RT|SV)|FILEMETHOD)\n |FILE(TIME)?|FORBID_REUSE|FOLLOWLOCATION|FAILONERROR|WRITE(FUNCTION|HEADER)|LOW_SPEED_(LIMIT|TIME)\n |AUTOREFERER)\n |PROXY_(HTTP|SOCKS(4|5))|PROTO_(SCP|SFTP|HTTP(S)?|TELNET|TFTP|DICT|FTP(S)?|FILE|LDAP(S)?|ALL)\n |E_((RECV|READ)_ERROR|GOT_NOTHING|MALFORMAT_USER\n |BAD_(CONTENT_ENCODING|CALLING_ORDER|PASSWORD_ENTERED|FUNCTION_ARGUMENT)\n |SSH|SSL_(CIPHER|CONNECT_ERROR|CERTPROBLEM|CACERT|PEER_CERTIFICATE|ENGINE_(NOTFOUND|SETFAILED))\n |SHARE_IN_USE|SEND_ERROR|HTTP_(RANGE_ERROR|NOT_FOUND|PORT_FAILED|POST_ERROR)\n |COULDNT_(RESOLVE_(HOST|PROXY)|CONNECT)|TOO_MANY_REDIRECTS|TELNET_OPTION_SYNTAX|OBSOLETE\n |OUT_OF_MEMORY|OPERATION|TIMEOUTED|OK|URL_MALFORMAT(_USER)?|UNSUPPORTED_PROTOCOL\n |UNKNOWN_TELNET_OPTION|PARTIAL_FILE\n |FTP_(BAD_DOWNLOAD_RESUME|SSL_FAILED|COULDNT_(RETR_FILE|GET_SIZE|STOR_FILE|SET_(BINARY|ASCII)|USE_REST)\n |CANT_(GET_HOST|RECONNECT)|USER_PASSWORD_INCORRECT|PORT_FAILED|QUOTE_ERROR|WRITE_ERROR\n |WEIRD_((PASS|PASV|SERVER|USER)_REPLY|227_FORMAT)|ACCESS_DENIED)\n |FILESIZE_EXCEEDED|FILE_COULDNT_READ_FILE|FUNCTION_NOT_FOUND|FAILED_INIT|WRITE_ERROR|LIBRARY_NOT_FOUND\n |LDAP_(SEARCH_FAILED|CANNOT_BIND|INVALID_URL)|ABORTED_BY_CALLBACK)\n |VERSION_NOW\n |FTP(METHOD_(MULTI|SINGLE|NO)CWD|SSL_(ALL|NONE|CONTROL|TRY)|AUTH_(DEFAULT|SSL|TLS))\n |AUTH_(ANY(SAFE)?|BASIC|DIGEST|GSSNEGOTIATE|NTLM))\n|CURL_(HTTP_VERSION_(1_(0|1)|NONE)|NETRC_(REQUIRED|IGNORED|OPTIONAL)|TIMECOND_(IF(UN)?MODSINCE|LASTMOD)\n |IPRESOLVE_(V(4|6)|WHATEVER)|VERSION_(SSL|IPV6|KERBEROS4|LIBZ))\n|IMAGETYPE_(GIF|XBM|BMP|SWF|COUNT|TIFF_(MM|II)|ICO|IFF|UNKNOWN|JB2|JPX|JP2|JPC|JPEG(2000)?|PSD|PNG|WBMP)\n|INPUT_(REQUEST|GET|SERVER|SESSION|COOKIE|POST|ENV)|ICONV_(MIME_DECODE_(STRICT|CONTINUE_ON_ERROR)|IMPL|VERSION)\n|DNS_(MX|SRV|SOA|HINFO|NS|NAPTR|CNAME|TXT|PTR|ANY|ALL|AAAA|A(6)?)\n|DOM(STRING_SIZE_ERR)\n|DOM_((SYNTAX|HIERARCHY_REQUEST|NO_(MODIFICATION_ALLOWED|DATA_ALLOWED)|NOT_(FOUND|SUPPORTED)|NAMESPACE\n |INDEX_SIZE|USE_ATTRIBUTE|VALID_(MODIFICATION|STATE|CHARACTER|ACCESS)|PHP|VALIDATION|WRONG_DOCUMENT)_ERR)\n|JSON_(HEX_(TAG|QUOT|AMP|APOS)|NUMERIC_CHECK|ERROR_(SYNTAX|STATE_MISMATCH|NONE|CTRL_CHAR|DEPTH|UTF8)|FORCE_OBJECT)\n|PREG_((D_UTF8(_OFFSET)?|NO|INTERNAL|(BACKTRACK|RECURSION)_LIMIT)_ERROR|GREP_INVERT\n |SPLIT_(NO_EMPTY|(DELIM|OFFSET)_CAPTURE)|SET_ORDER|OFFSET_CAPTURE|PATTERN_ORDER)\n|PSFS_(PASS_ON|ERR_FATAL|FEED_ME|FLAG_(NORMAL|FLUSH_(CLOSE|INC)))\n|PCRE_VERSION|POSIX_((F|R|W|X)_OK|S_IF(REG|BLK|SOCK|CHR|IFO))\n|FNM_(NOESCAPE|CASEFOLD|PERIOD|PATHNAME)\n|FILTER_(REQUIRE_(SCALAR|ARRAY)|NULL_ON_FAILURE|CALLBACK|DEFAULT|UNSAFE_RAW\n |SANITIZE_(MAGIC_QUOTES|STRING|STRIPPED|SPECIAL_CHARS|NUMBER_(INT|FLOAT)|URL\n |EMAIL|ENCODED|FULL_SPCIAL_CHARS)\n |VALIDATE_(REGEXP|BOOLEAN|INT|IP|URL|EMAIL|FLOAT)\n |FORCE_ARRAY\n |FLAG_(SCHEME_REQUIRED|STRIP_(BACKTICK|HIGH|LOW)|HOST_REQUIRED|NONE|NO_(RES|PRIV)_RANGE|ENCODE_QUOTES\n |IPV(4|6)|PATH_REQUIRED|EMPTY_STRING_NULL|ENCODE_(HIGH|LOW|AMP)|QUERY_REQUIRED\n |ALLOW_(SCIENTIFIC|HEX|THOUSAND|OCTAL|FRACTION)))\n|FILE_(BINARY|SKIP_EMPTY_LINES|NO_DEFAULT_CONTEXT|TEXT|IGNORE_NEW_LINES|USE_INCLUDE_PATH|APPEND)\n|FILEINFO_(RAW|MIME(_(ENCODING|TYPE))?|SYMLINK|NONE|CONTINUE|DEVICES|PRESERVE_ATIME)\n|FORCE_(DEFLATE|GZIP)\n|LIBXML_(XINCLUDE|NSCLEAN|NO(XMLDECL|BLANKS|NET|CDATA|ERROR|EMPTYTAG|ENT|WARNING)\n |COMPACT|DTD(VALID|LOAD|ATTR)|((DOTTED|LOADED)_)?VERSION|PARSEHUGE|ERR_(NONE|ERROR|FATAL|WARNING)))\n\\b", + "name": "support.constant.ext.php", + "captures": { + "1": { + "name": "punctuation.separator.inheritance.php" + } + } + }, + { + "match": + "(?x)\n(\\\\)?\\b\n(T_(RETURN|REQUIRE(_ONCE)?|GOTO|GLOBAL|(MINUS|MOD|MUL|XOR)_EQUAL|METHOD_C|ML_COMMENT|BREAK\n |BOOL_CAST|BOOLEAN_(AND|OR)|BAD_CHARACTER|SR(_EQUAL)?|STRING(_CAST|VARNAME)?|START_HEREDOC|STATIC\n |SWITCH|SL(_EQUAL)?|HALT_COMPILER|NS_(C|SEPARATOR)|NUM_STRING|NEW|NAMESPACE|CHARACTER|COMMENT\n |CONSTANT(_ENCAPSED_STRING)?|CONCAT_EQUAL|CONTINUE|CURLY_OPEN|CLOSE_TAG|CLONE|CLASS(_C)?\n |CASE|CATCH|TRY|THROW|IMPLEMENTS|ISSET|IS_((GREATER|SMALLER)_OR_EQUAL|(NOT_)?(IDENTICAL|EQUAL))\n |INSTANCEOF|INCLUDE(_ONCE)?|INC|INT_CAST|INTERFACE|INLINE_HTML|IF|OR_EQUAL|OBJECT_(CAST|OPERATOR)\n |OPEN_TAG(_WITH_ECHO)?|OLD_FUNCTION|DNUMBER|DIR|DIV_EQUAL|DOC_COMMENT|DOUBLE_(ARROW|CAST|COLON)\n |DOLLAR_OPEN_CURLY_BRACES|DO|DEC|DECLARE|DEFAULT|USE|UNSET(_CAST)?|PRINT|PRIVATE|PROTECTED|PUBLIC\n |PLUS_EQUAL|PAAMAYIM_NEKUDOTAYIM|EXTENDS|EXIT|EMPTY|ENCAPSED_AND_WHITESPACE\n |END(SWITCH|IF|DECLARE|FOR(EACH)?|WHILE)|END_HEREDOC|ECHO|EVAL|ELSE(IF)?|VAR(IABLE)?|FINAL|FILE\n |FOR(EACH)?|FUNC_C|FUNCTION|WHITESPACE|WHILE|LNUMBER|LIST|LINE|LOGICAL_(AND|OR|XOR)\n |ARRAY_(CAST)?|ABSTRACT|AS|AND_EQUAL))\n\\b", + "name": "support.constant.parser-token.php", + "captures": { + "1": { + "name": "punctuation.separator.inheritance.php" + } + } + }, + { + "match": "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "constant.other.php" + } + ] + }, + "function-parameters": { + "patterns": [ + { + "include": "#comments" + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.php" + }, + { + "begin": + "(?xi)\n(?:(\\?)\\s*)?(array) # Typehint\n\\s+((&)?\\s*(\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Variable name with possible reference\n\\s*(=)\\s*(array)\\s*(\\() # Default value", + "beginCaptures": { + "1": { + "name": "keyword.operator.nullable-type.php" + }, + "2": { + "name": "storage.type.php" + }, + "3": { + "name": "variable.other.php" + }, + "4": { + "name": "storage.modifier.reference.php" + }, + "5": { + "name": "punctuation.definition.variable.php" + }, + "6": { + "name": "keyword.operator.assignment.php" + }, + "7": { + "name": "support.function.construct.php" + }, + "8": { + "name": "punctuation.definition.array.begin.bracket.round.php" + } + }, + "contentName": "meta.array.php", + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.bracket.round.php" + } + }, + "name": "meta.function.parameter.array.php", + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#strings" + }, + { + "include": "#numbers" + } + ] + }, + { + "match": + "(?xi)\n(?:(\\?)\\s*)?(array|callable) # Typehint\n\\s+((&)?\\s*(\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Variable name with possible reference\n(?: # Optional default value\n \\s*(=)\\s*\n (?:\n (null)\n |\n (\\[)((?>[^\\[\\]]+|\\[\\g<8>\\])*)(\\])\n |((?:\\S*?\\(\\))|(?:\\S*?))\n )\n)?\n\\s*(?=,|\\)|/[/*]|\\#|$) # A closing parentheses (end of argument list) or a comma or a comment", + "name": "meta.function.parameter.array.php", + "captures": { + "1": { + "name": "keyword.operator.nullable-type.php" + }, + "2": { + "name": "storage.type.php" + }, + "3": { + "name": "variable.other.php" + }, + "4": { + "name": "storage.modifier.reference.php" + }, + "5": { + "name": "punctuation.definition.variable.php" + }, + "6": { + "name": "keyword.operator.assignment.php" + }, + "7": { + "name": "constant.language.php" + }, + "8": { + "name": "punctuation.section.array.begin.php" + }, + "9": { + "patterns": [ + { + "include": "#parameter-default-types" + } + ] + }, + "10": { + "name": "punctuation.section.array.end.php" + }, + "11": { + "name": "invalid.illegal.non-null-typehinted.php" + } + } + }, + { + "begin": + "(?xi)\n(?:(\\?)\\s*)?\n(\\\\?(?:[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*\\\\)*) # Optional namespace\n([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Typehinted class name\n\\s+((&)?\\s*(\\.\\.\\.)?(\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Variable name with possible reference", + "beginCaptures": { + "1": { + "name": "keyword.operator.nullable-type.php" + }, + "2": { + "name": "support.other.namespace.php", + "patterns": [ + { + "match": + "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "storage.type.php" + }, + { + "match": "\\\\", + "name": "punctuation.separator.inheritance.php" + } + ] + }, + "3": { + "name": "storage.type.php" + }, + "4": { + "name": "variable.other.php" + }, + "5": { + "name": "storage.modifier.reference.php" + }, + "6": { + "name": "keyword.operator.variadic.php" + }, + "7": { + "name": "punctuation.definition.variable.php" + } + }, + "end": "(?=,|\\)|/[/*]|\\#)", + "name": "meta.function.parameter.typehinted.php", + "patterns": [ + { + "begin": "=", + "beginCaptures": { + "0": { + "name": "keyword.operator.assignment.php" + } + }, + "end": "(?=,|\\)|/[/*]|\\#)", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + { + "captures": { + "1": { + "name": "variable.other.php" + }, + "2": { + "name": "storage.modifier.reference.php" + }, + "3": { + "name": "keyword.operator.variadic.php" + }, + "4": { + "name": "punctuation.definition.variable.php" + } + }, + "match": + "(?xi)\n((&)?\\s*(\\.\\.\\.)?(\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Variable name with possible reference\n\\s*(?=,|\\)|/[/*]|\\#|$) # A closing parentheses (end of argument list) or a comma or a comment", + "name": "meta.function.parameter.no-default.php" + }, + { + "begin": + "(?xi)\n((&)?\\s*(\\.\\.\\.)?(\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Variable name with possible reference\n\\s*(=)\\s*\n(?:(\\[)((?>[^\\[\\]]+|\\[\\g<6>\\])*)(\\]))? # Optional default type", + "beginCaptures": { + "1": { + "name": "variable.other.php" + }, + "2": { + "name": "storage.modifier.reference.php" + }, + "3": { + "name": "keyword.operator.variadic.php" + }, + "4": { + "name": "punctuation.definition.variable.php" + }, + "5": { + "name": "keyword.operator.assignment.php" + }, + "6": { + "name": "punctuation.section.array.begin.php" + }, + "7": { + "patterns": [ + { + "include": "#parameter-default-types" + } + ] + }, + "8": { + "name": "punctuation.section.array.end.php" + } + }, + "end": "(?=,|\\)|/[/*]|\\#)", + "name": "meta.function.parameter.default.php", + "patterns": [ + { + "include": "#parameter-default-types" + } + ] + } + ] + }, + "function-call": { + "patterns": [ + { + "begin": + "(?xi)\n(\n \\\\?(?<![a-z0-9_\\x{7f}-\\x{7fffffff}]) # Optional root namespace\n [a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]* # First namespace\n (?:\\\\[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)+ # Additional namespaces\n)\\s*(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#namespace" + }, + { + "match": + "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "entity.name.function.php" + } + ] + }, + "2": { + "name": "punctuation.definition.arguments.begin.bracket.round.php" + } + }, + "end": "\\)|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.arguments.end.bracket.round.php" + } + }, + "name": "meta.function-call.php", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": + "(?i)(\\\\)?(?<![a-z0-9_\\x{7f}-\\x{7fffffff}])([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)\\s*(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#namespace" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#support" + }, + { + "match": + "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "entity.name.function.php" + } + ] + }, + "3": { + "name": "punctuation.definition.arguments.begin.bracket.round.php" + } + }, + "end": "\\)|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.arguments.end.bracket.round.php" + } + }, + "name": "meta.function-call.php", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "match": "(?i)\\b(print|echo)\\b", + "name": "support.function.construct.output.php" + } + ] + }, + "heredoc": { + "patterns": [ + { + "begin": + "(?i)(?=<<<\\s*(\"?)([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)(\\1)\\s*$)", + "end": "(?!\\G)", + "name": "string.unquoted.heredoc.php", + "patterns": [ + { + "include": "#heredoc_interior" + } + ] + }, + { + "begin": "(?=<<<\\s*'([a-zA-Z_]+[a-zA-Z0-9_]*)'\\s*$)", + "end": "(?!\\G)", + "name": "string.unquoted.nowdoc.php", + "patterns": [ + { + "include": "#nowdoc_interior" + } + ] + } + ] + }, + "heredoc_interior": { + "patterns": [ + { + "begin": "(<<<)\\s*(\"?)(HTML)(\\2)(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "3": { + "name": "keyword.operator.heredoc.php" + }, + "5": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "text.html", + "end": "^(\\3)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.heredoc.php" + } + }, + "name": "meta.embedded.html", + "patterns": [ + { + "include": "#interpolation" + }, + { + "include": "text.html.basic" + } + ] + }, + { + "begin": "(<<<)\\s*(\"?)(XML)(\\2)(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "3": { + "name": "keyword.operator.heredoc.php" + }, + "5": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "text.xml", + "end": "^(\\3)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.heredoc.php" + } + }, + "name": "meta.embedded.xml", + "patterns": [ + { + "include": "#interpolation" + }, + { + "include": "text.xml" + } + ] + }, + { + "begin": "(<<<)\\s*(\"?)(SQL)(\\2)(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "3": { + "name": "keyword.operator.heredoc.php" + }, + "5": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "source.sql", + "end": "^(\\3)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.heredoc.php" + } + }, + "name": "meta.embedded.sql", + "patterns": [ + { + "include": "#interpolation" + }, + { + "include": "source.sql" + } + ] + }, + { + "begin": "(<<<)\\s*(\"?)(JAVASCRIPT|JS)(\\2)(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "3": { + "name": "keyword.operator.heredoc.php" + }, + "5": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "source.js", + "end": "^(\\3)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.heredoc.php" + } + }, + "name": "meta.embedded.js", + "patterns": [ + { + "include": "#interpolation" + }, + { + "include": "source.js" + } + ] + }, + { + "begin": "(<<<)\\s*(\"?)(JSON)(\\2)(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "3": { + "name": "keyword.operator.heredoc.php" + }, + "5": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "source.json", + "end": "^(\\3)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.heredoc.php" + } + }, + "name": "meta.embedded.json", + "patterns": [ + { + "include": "#interpolation" + }, + { + "include": "source.json" + } + ] + }, + { + "begin": "(<<<)\\s*(\"?)(CSS)(\\2)(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "3": { + "name": "keyword.operator.heredoc.php" + }, + "5": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "source.css", + "end": "^(\\3)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.heredoc.php" + } + }, + "name": "meta.embedded.css", + "patterns": [ + { + "include": "#interpolation" + }, + { + "include": "source.css" + } + ] + }, + { + "begin": "(<<<)\\s*(\"?)(REGEXP?)(\\2)(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "3": { + "name": "keyword.operator.heredoc.php" + }, + "5": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "string.regexp.heredoc.php", + "end": "^(\\3)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.heredoc.php" + } + }, + "patterns": [ + { + "include": "#interpolation" + }, + { + "match": "(\\\\){1,2}[.$^\\[\\]{}]", + "name": "constant.character.escape.regex.php" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.arbitrary-repitition.php" + }, + "3": { + "name": "punctuation.definition.arbitrary-repitition.php" + } + }, + "match": "({)\\d+(,\\d+)?(})", + "name": "string.regexp.arbitrary-repitition.php" + }, + { + "begin": "\\[(?:\\^?\\])?", + "captures": { + "0": { + "name": "punctuation.definition.character-class.php" + } + }, + "end": "\\]", + "name": "string.regexp.character-class.php", + "patterns": [ + { + "match": "\\\\[\\\\'\\[\\]]", + "name": "constant.character.escape.php" + } + ] + }, + { + "match": "[$^+*]", + "name": "keyword.operator.regexp.php" + }, + { + "begin": + "(?i)(?<=^|\\s)(#)\\s(?=[[a-z0-9_\\x{7f}-\\x{7fffffff},. \\t?!-][^\\x{00}-\\x{7f}]]*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.php" + } + }, + "end": "$", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "name": "comment.line.number-sign.php" + } + ] + }, + { + "begin": + "(?i)(<<<)\\s*(\"?)([a-z_\\x{7f}-\\x{7fffffff}]+[a-z0-9_\\x{7f}-\\x{7fffffff}]*)(\\2)(\\s*)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.php" + }, + "3": { + "name": "keyword.operator.heredoc.php" + }, + "5": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "end": "^(\\3)(?=;?$)", + "endCaptures": { + "1": { + "name": "keyword.operator.heredoc.php" + } + }, + "patterns": [ + { + "include": "#interpolation" + } + ] + } + ] + }, + "nowdoc_interior": { + "patterns": [ + { + "begin": "(<<<)\\s*'(HTML)'(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "2": { + "name": "keyword.operator.nowdoc.php" + }, + "3": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "text.html", + "end": "^(\\2)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.nowdoc.php" + } + }, + "name": "meta.embedded.html", + "patterns": [ + { + "include": "text.html.basic" + } + ] + }, + { + "begin": "(<<<)\\s*'(XML)'(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "2": { + "name": "keyword.operator.nowdoc.php" + }, + "3": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "text.xml", + "end": "^(\\2)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.nowdoc.php" + } + }, + "name": "meta.embedded.xml", + "patterns": [ + { + "include": "text.xml" + } + ] + }, + { + "begin": "(<<<)\\s*'(SQL)'(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "2": { + "name": "keyword.operator.nowdoc.php" + }, + "3": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "source.sql", + "end": "^(\\2)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.nowdoc.php" + } + }, + "name": "meta.embedded.sql", + "patterns": [ + { + "include": "source.sql" + } + ] + }, + { + "begin": "(<<<)\\s*'(JAVASCRIPT|JS)'(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "2": { + "name": "keyword.operator.nowdoc.php" + }, + "3": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "source.js", + "end": "^(\\2)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.nowdoc.php" + } + }, + "name": "meta.embedded.js", + "patterns": [ + { + "include": "source.js" + } + ] + }, + { + "begin": "(<<<)\\s*'(JSON)'(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "2": { + "name": "keyword.operator.nowdoc.php" + }, + "3": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "source.json", + "end": "^(\\2)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.nowdoc.php" + } + }, + "name": "meta.embedded.json", + "patterns": [ + { + "include": "source.json" + } + ] + }, + { + "begin": "(<<<)\\s*'(CSS)'(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "2": { + "name": "keyword.operator.nowdoc.php" + }, + "3": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "source.css", + "end": "^(\\2)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.nowdoc.php" + } + }, + "name": "meta.embedded.css", + "patterns": [ + { + "include": "source.css" + } + ] + }, + { + "begin": "(<<<)\\s*'(REGEXP?)'(\\s*)$", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + }, + "1": { + "name": "punctuation.definition.string.php" + }, + "2": { + "name": "keyword.operator.nowdoc.php" + }, + "3": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "contentName": "string.regexp.nowdoc.php", + "end": "^(\\2)(?=;?$)", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "keyword.operator.nowdoc.php" + } + }, + "patterns": [ + { + "match": "(\\\\){1,2}[.$^\\[\\]{}]", + "name": "constant.character.escape.regex.php" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.arbitrary-repitition.php" + }, + "3": { + "name": "punctuation.definition.arbitrary-repitition.php" + } + }, + "match": "({)\\d+(,\\d+)?(})", + "name": "string.regexp.arbitrary-repitition.php" + }, + { + "begin": "\\[(?:\\^?\\])?", + "captures": { + "0": { + "name": "punctuation.definition.character-class.php" + } + }, + "end": "\\]", + "name": "string.regexp.character-class.php", + "patterns": [ + { + "match": "\\\\[\\\\'\\[\\]]", + "name": "constant.character.escape.php" + } + ] + }, + { + "match": "[$^+*]", + "name": "keyword.operator.regexp.php" + }, + { + "begin": + "(?i)(?<=^|\\s)(#)\\s(?=[[a-z0-9_\\x{7f}-\\x{7fffffff},. \\t?!-][^\\x{00}-\\x{7f}]]*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.php" + } + }, + "end": "$", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "name": "comment.line.number-sign.php" + } + ] + }, + { + "begin": + "(?i)(<<<)\\s*'([a-z_\\x{7f}-\\x{7fffffff}]+[a-z0-9_\\x{7f}-\\x{7fffffff}]*)'(\\s*)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.php" + }, + "2": { + "name": "keyword.operator.nowdoc.php" + }, + "3": { + "name": "invalid.illegal.trailing-whitespace.php" + } + }, + "end": "^(\\2)(?=;?$)", + "endCaptures": { + "1": { + "name": "keyword.operator.nowdoc.php" + } + } + } + ] + }, + "instantiation": { + "begin": "(?i)(new)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.other.new.php" + } + }, + "end": "(?i)(?=[^a-z0-9_\\x{7f}-\\x{7fffffff}\\\\])", + "patterns": [ + { + "match": "(?i)(parent|static|self)(?![a-z0-9_\\x{7f}-\\x{7fffffff}])", + "name": "storage.type.php" + }, + { + "include": "#class-name" + }, + { + "include": "#variable-name" + } + ] + }, + "interpolation": { + "patterns": [ + { + "match": "\\\\[0-7]{1,3}", + "name": "constant.character.escape.octal.php" + }, + { + "match": "\\\\x[0-9A-Fa-f]{1,2}", + "name": "constant.character.escape.hex.php" + }, + { + "match": "\\\\u{[0-9A-Fa-f]+}", + "name": "constant.character.escape.unicode.php" + }, + { + "match": "\\\\[nrtvef$\\\\]", + "name": "constant.character.escape.php" + }, + { + "begin": "{(?=\\$.*?})", + "beginCaptures": { + "0": { + "name": "punctuation.definition.variable.php" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.definition.variable.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "include": "#variable-name" + } + ] + }, + "interpolation_double_quoted": { + "patterns": [ + { + "match": "\\\\\"", + "name": "constant.character.escape.php" + }, + { + "include": "#interpolation" + } + ] + }, + "invoke-call": { + "captures": { + "1": { + "name": "punctuation.definition.variable.php" + }, + "2": { + "name": "variable.other.php" + } + }, + "match": + "(?i)(\\$+)([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)(?=\\s*\\()", + "name": "meta.function-call.invoke.php" + }, + "namespace": { + "begin": + "(?i)(?:(namespace)|[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)?(\\\\)", + "beginCaptures": { + "1": { + "name": "variable.language.namespace.php" + }, + "2": { + "name": "punctuation.separator.inheritance.php" + } + }, + "end": "(?i)(?![a-z0-9_\\x{7f}-\\x{7fffffff}]*\\\\)", + "name": "support.other.namespace.php", + "patterns": [ + { + "match": "\\\\", + "name": "punctuation.separator.inheritance.php" + } + ] + }, + "numbers": { + "patterns": [ + { + "match": "0[xX][0-9a-fA-F]+", + "name": "constant.numeric.hex.php" + }, + { + "match": "0[bB][01]+", + "name": "constant.numeric.binary.php" + }, + { + "match": "0[0-7]+", + "name": "constant.numeric.octal.php" + }, + { + "match": + "(?x)\n(?:\n [0-9]*(\\.)[0-9]+(?:[eE][+-]?[0-9]+)?|\n [0-9]+(\\.)[0-9]*(?:[eE][+-]?[0-9]+)?|\n [0-9]+[eE][+-]?[0-9]+\n)", + "name": "constant.numeric.decimal.php", + "captures": { + "1": { + "name": "punctuation.separator.decimal.period.php" + }, + "2": { + "name": "punctuation.separator.decimal.period.php" + } + } + }, + { + "match": "0|[1-9][0-9]*", + "name": "constant.numeric.decimal.php" + } + ] + }, + "object": { + "patterns": [ + { + "begin": "(->)(\\$?{)", + "beginCaptures": { + "1": { + "name": "keyword.operator.class.php" + }, + "2": { + "name": "punctuation.definition.variable.php" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.definition.variable.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": + "(?i)(->)([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.class.php" + }, + "2": { + "name": "entity.name.function.php" + }, + "3": { + "name": "punctuation.definition.arguments.begin.bracket.round.php" + } + }, + "end": "\\)|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.arguments.end.bracket.round.php" + } + }, + "name": "meta.method-call.php", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "captures": { + "1": { + "name": "keyword.operator.class.php" + }, + "2": { + "name": "variable.other.property.php" + }, + "3": { + "name": "punctuation.definition.variable.php" + } + }, + "match": + "(?i)(->)((\\$+)?[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)?" + } + ] + }, + "parameter-default-types": { + "patterns": [ + { + "include": "#strings" + }, + { + "include": "#numbers" + }, + { + "include": "#string-backtick" + }, + { + "include": "#variables" + }, + { + "match": "=>", + "name": "keyword.operator.key.php" + }, + { + "match": "=", + "name": "keyword.operator.assignment.php" + }, + { + "match": "&(?=\\s*\\$)", + "name": "storage.modifier.reference.php" + }, + { + "begin": "(array)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "support.function.construct.php" + }, + "2": { + "name": "punctuation.definition.array.begin.bracket.round.php" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.bracket.round.php" + } + }, + "name": "meta.array.php", + "patterns": [ + { + "include": "#parameter-default-types" + } + ] + }, + { + "include": "#instantiation" + }, + { + "begin": + "(?xi)\n(?=[a-z0-9_\\x{7f}-\\x{7fffffff}\\\\]+(::)\n ([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)?\n)", + "end": "(?i)(::)([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)?", + "endCaptures": { + "1": { + "name": "keyword.operator.class.php" + }, + "2": { + "name": "constant.other.class.php" + } + }, + "patterns": [ + { + "include": "#class-name" + } + ] + }, + { + "include": "#constants" + } + ] + }, + "php_doc": { + "patterns": [ + { + "match": "^(?!\\s*\\*).*?(?:(?=\\*\\/)|$\\n?)", + "name": "invalid.illegal.missing-asterisk.phpdoc.php" + }, + { + "captures": { + "1": { + "name": "keyword.other.phpdoc.php" + }, + "3": { + "name": "storage.modifier.php" + }, + "4": { + "name": "invalid.illegal.wrong-access-type.phpdoc.php" + } + }, + "match": "^\\s*\\*\\s*(@access)\\s+((public|private|protected)|(.+))\\s*$" + }, + { + "captures": { + "1": { + "name": "keyword.other.phpdoc.php" + }, + "2": { + "name": "markup.underline.link.php" + } + }, + "match": "(@xlink)\\s+(.+)\\s*$" + }, + { + "begin": + "(@(?:global|param|property(-(read|write))?|return|throws|var))\\s+(?=[A-Za-z_\\x{7f}-\\x{7fffffff}\\\\]|\\()", + "beginCaptures": { + "1": { + "name": "keyword.other.phpdoc.php" + } + }, + "end": "(?=\\s|\\*/)", + "contentName": "meta.other.type.phpdoc.php", + "patterns": [ + { + "include": "#php_doc_types_array_multiple" + }, + { + "include": "#php_doc_types_array_single" + }, + { + "include": "#php_doc_types" + } + ] + }, + { + "match": + "(?x)\n@\n(\n api|abstract|author|category|copyright|example|global|inherit[Dd]oc|internal|\n license|link|method|property(-(read|write))?|package|param|return|see|since|source|\n static|subpackage|throws|todo|var|version|uses|deprecated|final|ignore\n)\\b", + "name": "keyword.other.phpdoc.php" + }, + { + "captures": { + "1": { + "name": "keyword.other.phpdoc.php" + } + }, + "match": "{(@(link|inherit[Dd]oc)).+?}", + "name": "meta.tag.inline.phpdoc.php" + } + ] + }, + "php_doc_types": { + "match": + "(?i)[a-z_\\x{7f}-\\x{7fffffff}\\\\][a-z0-9_\\x{7f}-\\x{7fffffff}\\\\]*(\\|[a-z_\\x{7f}-\\x{7fffffff}\\\\][a-z0-9_\\x{7f}-\\x{7fffffff}\\\\]*)*", + "captures": { + "0": { + "patterns": [ + { + "match": + "(?x)\\b\n(string|integer|int|boolean|bool|float|double|object|mixed\n|array|resource|void|null|callback|false|true|self)\\b", + "name": "keyword.other.type.php" + }, + { + "include": "#class-name" + }, + { + "match": "\\|", + "name": "punctuation.separator.delimiter.php" + } + ] + } + } + }, + "php_doc_types_array_multiple": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.type.begin.bracket.round.phpdoc.php" + } + }, + "end": "(\\))(\\[\\])|(?=\\*/)", + "endCaptures": { + "1": { + "name": "punctuation.definition.type.end.bracket.round.phpdoc.php" + }, + "2": { + "name": "keyword.other.array.phpdoc.php" + } + }, + "patterns": [ + { + "include": "#php_doc_types_array_multiple" + }, + { + "include": "#php_doc_types_array_single" + }, + { + "include": "#php_doc_types" + }, + { + "match": "\\|", + "name": "punctuation.separator.delimiter.php" + } + ] + }, + "php_doc_types_array_single": { + "match": + "(?i)([a-z_\\x{7f}-\\x{7fffffff}\\\\][a-z0-9_\\x{7f}-\\x{7fffffff}\\\\]*)(\\[\\])", + "captures": { + "1": { + "patterns": [ + { + "include": "#php_doc_types" + } + ] + }, + "2": { + "name": "keyword.other.array.phpdoc.php" + } + } + }, + "regex-double-quoted": { + "begin": "\"/(?=(\\\\.|[^\"/])++/[imsxeADSUXu]*\")", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.php" + } + }, + "end": "(/)([imsxeADSUXu]*)(\")", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.php" + } + }, + "name": "string.regexp.double-quoted.php", + "patterns": [ + { + "match": "(\\\\){1,2}[.$^\\[\\]{}]", + "name": "constant.character.escape.regex.php" + }, + { + "include": "#interpolation_double_quoted" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.arbitrary-repetition.php" + }, + "3": { + "name": "punctuation.definition.arbitrary-repetition.php" + } + }, + "match": "({)\\d+(,\\d+)?(})", + "name": "string.regexp.arbitrary-repetition.php" + }, + { + "begin": "\\[(?:\\^?\\])?", + "captures": { + "0": { + "name": "punctuation.definition.character-class.php" + } + }, + "end": "\\]", + "name": "string.regexp.character-class.php", + "patterns": [ + { + "include": "#interpolation_double_quoted" + } + ] + }, + { + "match": "[$^+*]", + "name": "keyword.operator.regexp.php" + } + ] + }, + "regex-single-quoted": { + "begin": "'/(?=(\\\\(?:\\\\(?:\\\\[\\\\']?|[^'])|.)|[^'/])++/[imsxeADSUXu]*')", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.php" + } + }, + "end": "(/)([imsxeADSUXu]*)(')", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.php" + } + }, + "name": "string.regexp.single-quoted.php", + "patterns": [ + { + "include": "#single_quote_regex_escape" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.arbitrary-repetition.php" + }, + "3": { + "name": "punctuation.definition.arbitrary-repetition.php" + } + }, + "match": "({)\\d+(,\\d+)?(})", + "name": "string.regexp.arbitrary-repetition.php" + }, + { + "begin": "\\[(?:\\^?\\])?", + "captures": { + "0": { + "name": "punctuation.definition.character-class.php" + } + }, + "end": "\\]", + "name": "string.regexp.character-class.php" + }, + { + "match": "[$^+*]", + "name": "keyword.operator.regexp.php" + } + ] + }, + "scope-resolution": { + "patterns": [ + { + "match": + "([A-Za-z_\\x{7f}-\\x{7fffffff}\\\\][A-Za-z0-9_\\x{7f}-\\x{7fffffff}\\\\]*)(?=\\s*::)", + "captures": { + "1": { + "patterns": [ + { + "match": "\\b(self|static|parent)\\b", + "name": "storage.type.php" + }, + { + "include": "#class-name" + }, + { + "include": "#variable-name" + } + ] + } + } + }, + { + "begin": + "(?i)(::)\\s*([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.class.php" + }, + "2": { + "name": "entity.name.function.php" + }, + "3": { + "name": "punctuation.definition.arguments.begin.bracket.round.php" + } + }, + "end": "\\)|(?=\\?>)", + "endCaptures": { + "0": { + "name": "punctuation.definition.arguments.end.bracket.round.php" + } + }, + "name": "meta.method-call.static.php", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "match": "(?i)(::)\\s*(class)\\b", + "captures": { + "1": { + "name": "keyword.operator.class.php" + }, + "2": { + "name": "keyword.other.class.php" + } + } + }, + { + "match": + "(?xi)\n(::)\\s*\n(?:\n ((\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Variable\n |\n ([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*) # Constant\n)?", + "captures": { + "1": { + "name": "keyword.operator.class.php" + }, + "2": { + "name": "variable.other.class.php" + }, + "3": { + "name": "punctuation.definition.variable.php" + }, + "4": { + "name": "constant.other.class.php" + } + } + } + ] + }, + "single_quote_regex_escape": { + "match": "\\\\(?:\\\\(?:\\\\[\\\\']?|[^'])|.)", + "name": "constant.character.escape.php" + }, + "sql-string-double-quoted": { + "begin": "\"\\s*(?=(SELECT|INSERT|UPDATE|DELETE|CREATE|REPLACE|ALTER|AND)\\b)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.php" + } + }, + "contentName": "source.sql.embedded.php", + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.php" + } + }, + "name": "string.quoted.double.sql.php", + "patterns": [ + { + "match": "(#)(\\\\\"|[^\"])*(?=\"|$)", + "name": "comment.line.number-sign.sql", + "captures": { + "1": { + "name": "punctuation.definition.comment.sql" + } + } + }, + { + "match": "(--)(\\\\\"|[^\"])*(?=\"|$)", + "name": "comment.line.double-dash.sql", + "captures": { + "1": { + "name": "punctuation.definition.comment.sql" + } + } + }, + { + "match": "\\\\[\\\\\"`']", + "name": "constant.character.escape.php" + }, + { + "match": "'(?=((\\\\')|[^'\"])*(\"|$))", + "name": "string.quoted.single.unclosed.sql" + }, + { + "match": "`(?=((\\\\`)|[^`\"])*(\"|$))", + "name": "string.quoted.other.backtick.unclosed.sql" + }, + { + "begin": "'", + "end": "'", + "name": "string.quoted.single.sql", + "patterns": [ + { + "include": "#interpolation_double_quoted" + } + ] + }, + { + "begin": "`", + "end": "`", + "name": "string.quoted.other.backtick.sql", + "patterns": [ + { + "include": "#interpolation_double_quoted" + } + ] + }, + { + "include": "#interpolation_double_quoted" + }, + { + "include": "source.sql" + } + ] + }, + "sql-string-single-quoted": { + "begin": "'\\s*(?=(SELECT|INSERT|UPDATE|DELETE|CREATE|REPLACE|ALTER|AND)\\b)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.php" + } + }, + "contentName": "source.sql.embedded.php", + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.php" + } + }, + "name": "string.quoted.single.sql.php", + "patterns": [ + { + "match": "(#)(\\\\'|[^'])*(?='|$)", + "name": "comment.line.number-sign.sql", + "captures": { + "1": { + "name": "punctuation.definition.comment.sql" + } + } + }, + { + "match": "(--)(\\\\'|[^'])*(?='|$)", + "name": "comment.line.double-dash.sql", + "captures": { + "1": { + "name": "punctuation.definition.comment.sql" + } + } + }, + { + "match": "\\\\[\\\\'`\"]", + "name": "constant.character.escape.php" + }, + { + "match": "`(?=((\\\\`)|[^`'])*('|$))", + "name": "string.quoted.other.backtick.unclosed.sql" + }, + { + "match": "\"(?=((\\\\\")|[^\"'])*('|$))", + "name": "string.quoted.double.unclosed.sql" + }, + { + "include": "source.sql" + } + ] + }, + "string-backtick": { + "begin": "`", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.php" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.php" + } + }, + "name": "string.interpolated.php", + "patterns": [ + { + "match": "\\\\`", + "name": "constant.character.escape.php" + }, + { + "include": "#interpolation" + } + ] + }, + "string-double-quoted": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.php" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.php" + } + }, + "name": "string.quoted.double.php", + "patterns": [ + { + "include": "#interpolation_double_quoted" + } + ] + }, + "string-single-quoted": { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.php" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.php" + } + }, + "name": "string.quoted.single.php", + "patterns": [ + { + "match": "\\\\[\\\\']", + "name": "constant.character.escape.php" + } + ] + }, + "strings": { + "patterns": [ + { + "include": "#regex-double-quoted" + }, + { + "include": "#sql-string-double-quoted" + }, + { + "include": "#string-double-quoted" + }, + { + "include": "#regex-single-quoted" + }, + { + "include": "#sql-string-single-quoted" + }, + { + "include": "#string-single-quoted" + } + ] + }, + "support": { + "patterns": [ + { + "match": + "(?xi)\n\\b\napc_(\n store|sma_info|compile_file|clear_cache|cas|cache_info|inc|dec|define_constants|delete(_file)?|\n exists|fetch|load_constants|add|bin_(dump|load)(file)?\n)\\b", + "name": "support.function.apc.php" + }, + { + "match": + "(?xi)\\b\n(\n shuffle|sizeof|sort|next|nat(case)?sort|count|compact|current|in_array|usort|uksort|uasort|\n pos|prev|end|each|extract|ksort|key(_exists)?|krsort|list|asort|arsort|rsort|reset|range|\n array(_(shift|sum|splice|search|slice|chunk|change_key_case|count_values|column|combine|\n (diff|intersect)(_(u)?(key|assoc))?|u(diff|intersect)(_(u)?assoc)?|unshift|unique|\n pop|push|pad|product|values|keys|key_exists|filter|fill(_keys)?|flip|walk(_recursive)?|\n reduce|replace(_recursive)?|reverse|rand|multisort|merge(_recursive)?|map)?)\n)\\b", + "name": "support.function.array.php" + }, + { + "match": + "(?xi)\\b\n(\n show_source|sys_getloadavg|sleep|highlight_(file|string)|constant|connection_(aborted|status)|\n time_(nanosleep|sleep_until)|ignore_user_abort|die|define(d)?|usleep|uniqid|unpack|__halt_compiler|\n php_(check_syntax|strip_whitespace)|pack|eval|exit|get_browser\n)\\b", + "name": "support.function.basic_functions.php" + }, + { + "match": "(?i)\\bbc(scale|sub|sqrt|comp|div|pow(mod)?|add|mod|mul)\\b", + "name": "support.function.bcmath.php" + }, + { + "match": "(?i)\\bblenc_encrypt\\b", + "name": "support.function.blenc.php" + }, + { + "match": + "(?i)\\bbz(compress|close|open|decompress|errstr|errno|error|flush|write|read)\\b", + "name": "support.function.bz2.php" + }, + { + "match": + "(?xi)\\b\n(\n (French|Gregorian|Jewish|Julian)ToJD|cal_(to_jd|info|days_in_month|from_jd)|unixtojd|\n jdto(unix|jewish)|easter_(date|days)|JD(MonthName|To(Gregorian|Julian|French)|DayOfWeek)\n)\\b", + "name": "support.function.calendar.php" + }, + { + "match": + "(?xi)\\b\n(\n class_alias|all_user_method(_array)?|is_(a|subclass_of)|__autoload|(class|interface|method|property|trait)_exists|\n get_(class(_(vars|methods))?|(called|parent)_class|object_vars|declared_(classes|interfaces|traits))\n)\\b", + "name": "support.function.classobj.php" + }, + { + "match": + "(?xi)\\b\n(\n com_(create_guid|print_typeinfo|event_sink|load_typelib|get_active_object|message_pump)|\n variant_(sub|set(_type)?|not|neg|cast|cat|cmp|int|idiv|imp|or|div|date_(from|to)_timestamp|\n pow|eqv|fix|and|add|abs|round|get_type|xor|mod|mul)\n)\\b", + "name": "support.function.com.php" + }, + { + "begin": "(?i)\\b(isset|unset|eval|empty|list)\\b", + "name": "support.function.construct.php" + }, + { + "match": "(?i)\\b(print|echo)\\b", + "name": "support.function.construct.output.php" + }, + { + "match": + "(?i)\\bctype_(space|cntrl|digit|upper|punct|print|lower|alnum|alpha|graph|xdigit)\\b", + "name": "support.function.ctype.php" + }, + { + "match": + "(?xi)\\b\ncurl_(\n share_(close|init|setopt)|strerror|setopt(_array)?|copy_handle|close|init|unescape|pause|escape|\n errno|error|exec|version|file_create|reset|getinfo|\n multi_(strerror|setopt|select|close|init|info_read|(add|remove)_handle|getcontent|exec)\n)\\b", + "name": "support.function.curl.php" + }, + { + "match": + "(?xi)\\b\n(\n strtotime|str[fp]time|checkdate|time|timezone_name_(from_abbr|get)|idate|\n timezone_((location|offset|transitions|version)_get|(abbreviations|identifiers)_list|open)|\n date(_(sun(rise|set)|sun_info|sub|create(_(immutable_)?from_format)?|timestamp_(get|set)|timezone_(get|set)|time_set|\n isodate_set|interval_(create_from_date_string|format)|offset_get|diff|default_timezone_(get|set)|date_set|\n parse(_from_format)?|format|add|get_last_errors|modify))?|\n localtime|get(date|timeofday)|gm(strftime|date|mktime)|microtime|mktime\n)\\b", + "name": "support.function.datetime.php" + }, + { + "match": + "(?i)\\bdba_(sync|handlers|nextkey|close|insert|optimize|open|delete|popen|exists|key_split|firstkey|fetch|list|replace)\\b", + "name": "support.function.dba.php" + }, + { + "match": + "(?i)\\bdbx_(sort|connect|compare|close|escape_string|error|query|fetch_row)\\b", + "name": "support.function.dbx.php" + }, + { + "match": + "(?i)\\b(scandir|chdir|chroot|closedir|opendir|dir|rewinddir|readdir|getcwd)\\b", + "name": "support.function.dir.php" + }, + { + "match": + "(?xi)\\b\neio_(\n sync(fs)?|sync_file_range|symlink|stat(vfs)?|sendfile|set_min_parallel|set_max_(idle|poll_(reqs|time)|parallel)|\n seek|n(threads|op|pending|reqs|ready)|chown|chmod|custom|close|cancel|truncate|init|open|dup2|unlink|utime|poll|\n event_loop|f(sync|stat(vfs)?|chown|chmod|truncate|datasync|utime|allocate)|write|lstat|link|rename|realpath|\n read(ahead|dir|link)?|rmdir|get_(event_stream|last_error)|grp(_(add|cancel|limit))?|mknod|mkdir|busy\n)\\b", + "name": "support.function.eio.php" + }, + { + "match": + "(?xi)\\b\nenchant_(\n dict_(store_replacement|suggest|check|is_in_session|describe|quick_check|add_to_(personal|session)|get_error)|\n broker_(set_ordering|init|dict_exists|describe|free(_dict)?|list_dicts|request_(pwl_)?dict|get_error)\n)\\b", + "name": "support.function.enchant.php" + }, + { + "match": "(?i)\\bsplit(i)?|sql_regcase|ereg(i)?(_replace)?\\b", + "name": "support.function.ereg.php" + }, + { + "match": + "(?i)\\b((restore|set)_(error_handler|exception_handler)|trigger_error|debug_(print_)?backtrace|user_error|error_(log|reporting|get_last))\\b", + "name": "support.function.errorfunc.php" + }, + { + "match": + "(?i)\\bshell_exec|system|passthru|proc_(nice|close|terminate|open|get_status)|escapeshell(arg|cmd)|exec\\b", + "name": "support.function.exec.php" + }, + { + "match": + "(?i)\\b(exif_(thumbnail|tagname|imagetype|read_data)|read_exif_data)\\b", + "name": "support.function.exif.php" + }, + { + "match": + "(?xi)\\b\nfann_(\n (duplicate|length|merge|shuffle|subset)_train_data|scale_(train(_data)?|(input|output)(_train_data)?)|\n set_(scaling_params|sarprop_(step_error_(shift|threshold_factor)|temperature|weight_decay_shift)|\n cascade_(num_candidate_groups|candidate_(change_fraction|limit|stagnation_epochs)|\n output_(change_fraction|stagnation_epochs)|weight_multiplier|activation_(functions|steepnesses)|\n (max|min)_(cand|out)_epochs)|\n callback|training_algorithm|train_(error|stop)_function|(input|output)_scaling_params|error_log|\n quickprop_(decay|mu)|weight(_array)?|learning_(momentum|rate)|bit_fail_limit|\n activation_(function|steepness)(_(hidden|layer|output))?|\n rprop_((decrease|increase)_factor|delta_(max|min|zero)))|\n save(_train)?|num_(input|output)_train_data|copy|clear_scaling_params|cascadetrain_on_(file|data)|\n create_((sparse|shortcut|standard)(_array)?|train(_from_callback)?|from_file)|\n test(_data)?|train(_(on_(file|data)|epoch))?|init_weights|descale_(input|output|train)|destroy(_train)?|\n print_error|run|reset_(MSE|err(no|str))|read_train_from_file|randomize_weights|\n get_(sarprop_(step_error_(shift|threshold_factor)|temperature|weight_decay_shift)|num_(input|output|layers)|\n network_type|MSE|connection_(array|rate)|bias_array|bit_fail(_limit)?|\n cascade_(num_(candidates|candidate_groups)|(candidate|output)_(change_fraction|limit|stagnation_epochs)|\n weight_multiplier|activation_(functions|steepnesses)(_count)?|(max|min)_(cand|out)_epochs)|\n total_(connections|neurons)|training_algorithm|train_(error|stop)_function|err(no|str)|\n quickprop_(decay|mu)|learning_(momentum|rate)|layer_array|activation_(function|steepness)|\n rprop_((decrease|increase)_factor|delta_(max|min|zero)))\n)\\b", + "name": "support.function.fann.php" + }, + { + "match": + "(?xi)\\b\n(\n symlink|stat|set_file_buffer|chown|chgrp|chmod|copy|clearstatcache|touch|tempnam|tmpfile|\n is_(dir|(uploaded_)?file|executable|link|readable|writ(e)?able)|disk_(free|total)_space|diskfreespace|\n dirname|delete|unlink|umask|pclose|popen|pathinfo|parse_ini_(file|string)|fscanf|fstat|fseek|fnmatch|\n fclose|ftell|ftruncate|file(size|[acm]time|type|inode|owner|perms|group)?|file_(exists|(get|put)_contents)|\n f(open|puts|putcsv|passthru|eof|flush|write|lock|read|gets(s)?|getc(sv)?)|lstat|lchown|lchgrp|link(info)?|\n rename|rewind|read(file|link)|realpath(_cache_(get|size))?|rmdir|glob|move_uploaded_file|mkdir|basename\n)\\b", + "name": "support.function.file.php" + }, + { + "match": + "(?i)\\b(finfo_(set_flags|close|open|file|buffer)|mime_content_type)\\b", + "name": "support.function.fileinfo.php" + }, + { + "match": "(?i)\\bfilter_(has_var|input(_array)?|id|var(_array)?|list)\\b", + "name": "support.function.filter.php" + }, + { + "match": "(?i)\\bfastcgi_finish_request\\b", + "name": "support.function.fpm.php" + }, + { + "match": + "(?i)\\b(call_user_(func|method)(_array)?|create_function|unregister_tick_function|forward_static_call(_array)?|function_exists|func_(num_args|get_arg(s)?)|register_(shutdown|tick)_function|get_defined_functions)\\b", + "name": "support.function.funchand.php" + }, + { + "match": + "(?i)\\b((n)?gettext|textdomain|d((n)?gettext|c(n)?gettext)|bind(textdomain|_textdomain_codeset))\\b", + "name": "support.function.gettext.php" + }, + { + "match": + "(?xi)\\b\ngmp_(\n scan[01]|strval|sign|sub|setbit|sqrt(rem)?|hamdist|neg|nextprime|com|clrbit|cmp|testbit|\n intval|init|invert|import|or|div(exact)?|div_(q|qr|r)|jacobi|popcount|pow(m)?|perfect_square|\n prob_prime|export|fact|legendre|and|add|abs|root(rem)?|random(_(bits|range))?|gcd(ext)?|xor|mod|mul\n)\\b", + "name": "support.function.gmp.php" + }, + { + "match": + "(?i)\\bhash(_(hmac(_file)?|copy|init|update(_(file|stream))?|pbkdf2|equals|file|final|algos))?\\b", + "name": "support.function.hash.php" + }, + { + "match": + "(?xi)\\b\n(\n http_(support|send_(status|stream|content_(disposition|type)|data|file|last_modified)|head|\n negotiate_(charset|content_type|language)|chunked_decode|cache_(etag|last_modified)|throttle|\n inflate|deflate|date|post_(data|fields)|put_(data|file|stream)|persistent_handles_(count|clean|ident)|\n parse_(cookie|headers|message|params)|redirect|request(_(method_(exists|name|(un)?register)|body_encode))?|\n get(_request_(headers|body(_stream)?))?|match_(etag|modified|request_header)|build_(cookie|str|url))|\n ob_(etag|deflate|inflate)handler\n)\\b", + "name": "support.function.http.php" + }, + { + "match": + "(?i)\\b(iconv(_(str(pos|len|rpos)|substr|(get|set)_encoding|mime_(decode(_headers)?|encode)))?|ob_iconv_handler)\\b", + "name": "support.function.iconv.php" + }, + { + "match": + "(?i)\\biis_((start|stop)_(service|server)|set_(script_map|server_rights|dir_security|app_settings)|(add|remove)_server|get_(script_map|service_state|server_(rights|by_(comment|path))|dir_security))\\b", + "name": "support.function.iisfunc.php" + }, + { + "match": + "(?xi)\\b\n(\n iptc(embed|parse)|(jpeg|png)2wbmp|gd_info|getimagesize(fromstring)?|\n image(s[xy]|scale|(char|string)(up)?|set(style|thickness|tile|interpolation|pixel|brush)|savealpha|\n convolution|copy(resampled|resized|merge(gray)?)?|colors(forindex|total)|\n color(set|closest(alpha|hwb)?|transparent|deallocate|(allocate|exact|resolve)(alpha)?|at|match)|\n crop(auto)?|create(truecolor|from(string|jpeg|png|wbmp|webp|gif|gd(2(part)?)?|xpm|xbm))?|\n types|ttf(bbox|text)|truecolortopalette|istruecolor|interlace|2wbmp|destroy|dashedline|jpeg|\n _type_to_(extension|mime_type)|ps(slantfont|text|(encode|extend|free|load)font|bbox)|png|polygon|\n palette(copy|totruecolor)|ellipse|ft(text|bbox)|filter|fill|filltoborder|\n filled(arc|ellipse|polygon|rectangle)|font(height|width)|flip|webp|wbmp|line|loadfont|layereffect|\n antialias|affine(matrix(concat|get))?|alphablending|arc|rotate|rectangle|gif|gd(2)?|gammacorrect|\n grab(screen|window)|xbm)\n)\\b", + "name": "support.function.image.php" + }, + { + "match": + "(?xi)\\b\n(\n sys_get_temp_dir|set_(time_limit|include_path|magic_quotes_runtime)|cli_(get|set)_process_title|\n ini_(alter|get(_all)?|restore|set)|zend_(thread_id|version|logo_guid)|dl|php(credits|info|version)|\n php_(sapi_name|ini_(scanned_files|loaded_file)|uname|logo_guid)|putenv|extension_loaded|version_compare|\n assert(_options)?|restore_include_path|gc_(collect_cycles|disable|enable(d)?)|getopt|\n get_(cfg_var|current_user|defined_constants|extension_funcs|include_path|included_files|loaded_extensions|\n magic_quotes_(gpc|runtime)|required_files|resources)|\n get(env|lastmod|rusage|my(inode|[gup]id))|\n memory_get_(peak_)?usage|main|magic_quotes_runtime\n)\\b", + "name": "support.function.info.php" + }, + { + "match": + "(?xi)\\b\nibase_(\n set_event_handler|service_(attach|detach)|server_info|num_(fields|params)|name_result|connect|\n commit(_ret)?|close|trans|delete_user|drop_db|db_info|pconnect|param_info|prepare|err(code|msg)|\n execute|query|field_info|fetch_(assoc|object|row)|free_(event_handler|query|result)|wait_event|\n add_user|affected_rows|rollback(_ret)?|restore|gen_id|modify_user|maintain_db|backup|\n blob_(cancel|close|create|import|info|open|echo|add|get)\n)\\b", + "name": "support.function.interbase.php" + }, + { + "match": + "(?xi)\\b\n(\n normalizer_(normalize|is_normalized)|idn_to_(unicode|utf8|ascii)|\n numfmt_(set_(symbol|(text_)?attribute|pattern)|create|(parse|format)(_currency)?|\n get_(symbol|(text_)?attribute|pattern|error_(code|message)|locale))|\n collator_(sort(_with_sort_keys)?|set_(attribute|strength)|compare|create|asort|\n get_(strength|sort_key|error_(code|message)|locale|attribute))|\n transliterator_(create(_(inverse|from_rules))?|transliterate|list_ids|get_error_(code|message))|\n intl(cal|tz)_get_error_(code|message)|intl_(is_failure|error_name|get_error_(code|message))|\n datefmt_(set_(calendar|lenient|pattern|timezone(_id)?)|create|is_lenient|parse|format(_object)?|localtime|\n get_(calendar(_object)?|time(type|zone(_id)?)|datetype|pattern|error_(code|message)|locale))|\n locale_(set_default|compose|canonicalize|parse|filter_matches|lookup|accept_from_http|\n get_(script|display_(script|name|variant|language|region)|default|primary_language|keywords|all_variants|region))|\n resourcebundle_(create|count|locales|get(_(error_(code|message)))?)|\n grapheme_(str(i?str|r?i?pos|len)|substr|extract)|\n msgfmt_(set_pattern|create|(format|parse)(_message)?|get_(pattern|error_(code|message)|locale))\n)\\b", + "name": "support.function.intl.php" + }, + { + "match": "(?i)\\bjson_(decode|encode|last_error(_msg)?)\\b", + "name": "support.function.json.php" + }, + { + "match": + "(?xi)\\b\nldap_(\n start|tls|sort|search|sasl_bind|set_(option|rebind_proc)|(first|next)_(attribute|entry|reference)|\n connect|control_paged_result(_response)?|count_entries|compare|close|t61_to_8859|8859_to_t61|\n dn2ufn|delete|unbind|parse_(reference|result)|escape|errno|err2str|error|explode_dn|bind|\n free_result|list|add|rename|read|get_(option|dn|entries|values(_len)?|attributes)|modify(_batch)?|\n mod_(add|del|replace)\n)\\b", + "name": "support.function.ldap.php" + }, + { + "match": + "(?i)\\blibxml_(set_(streams_context|external_entity_loader)|clear_errors|disable_entity_loader|use_internal_errors|get_(errors|last_error))\\b", + "name": "support.function.libxml.php" + }, + { + "match": "(?i)\\b(ezmlm_hash|mail)\\b", + "name": "support.function.mail.php" + }, + { + "match": + "(?xi)\\b\n(\n (a)?(cos|sin|tan)(h)?|sqrt|srand|hypot|hexdec|ceil|is_(nan|(in)?finite)|octdec|dec(hex|oct|bin)|deg2rad|\n pi|pow|exp(m1)?|floor|fmod|lcg_value|log(1(p|0))?|atan2|abs|round|rand|rad2deg|getrandmax|\n mt_(srand|rand|getrandmax)|max|min|bindec|base_convert\n)\\b", + "name": "support.function.math.php" + }, + { + "match": + "(?xi)\\b\nmb_(\n str(cut|str|to(lower|upper)|istr|ipos|imwidth|pos|width|len|rchr|richr|ripos|rpos)|\n substitute_character|substr(_count)?|split|send_mail|http_(input|output)|check_encoding|\n convert_(case|encoding|kana|variables)|internal_encoding|output_handler|decode_(numericentity|mimeheader)|\n detect_(encoding|order)|parse_str|preferred_mime_name|encoding_aliases|encode_(numericentity|mimeheader)|\n ereg(i(_replace)?)?|ereg_(search(_(get(pos|regs)|init|regs|(set)?pos))?|replace(_callback)?|match)|\n list_encodings|language|regex_(set_options|encoding)|get_info\n)\\b", + "name": "support.function.mbstring.php" + }, + { + "match": + "(?xi)\\b\n(\n mcrypt_(\n cfb|create_iv|cbc|ofb|decrypt|encrypt|ecb|list_(algorithms|modes)|generic(_((de)?init|end))?|\n enc_(self_test|is_block_(algorithm|algorithm_mode|mode)|\n get_(supported_key_sizes|(block|iv|key)_size|(algorithms|modes)_name))|\n get_(cipher_name|(block|iv|key)_size)|\n module_(close|self_test|is_block_(algorithm|algorithm_mode|mode)|open|\n get_(supported_key_sizes|algo_(block|key)_size)))|\n mdecrypt_generic\n)\\b", + "name": "support.function.mcrypt.php" + }, + { + "match": "(?i)\\bmemcache_debug\\b", + "name": "support.function.memcache.php" + }, + { + "match": "(?i)\\bmhash(_(count|keygen_s2k|get_(hash_name|block_size)))?\\b", + "name": "support.function.mhash.php" + }, + { + "match": + "(?i)\\b(log_(cmd_(insert|delete|update)|killcursor|write_batch|reply|getmore)|bson_(decode|encode))\\b", + "name": "support.function.mongo.php" + }, + { + "match": + "(?xi)\\b\nmysql_(\n stat|set_charset|select_db|num_(fields|rows)|connect|client_encoding|close|create_db|escape_string|\n thread_id|tablename|insert_id|info|data_seek|drop_db|db_(name|query)|unbuffered_query|pconnect|ping|\n errno|error|query|field_(seek|name|type|table|flags|len)|fetch_(object|field|lengths|assoc|array|row)|\n free_result|list_(tables|dbs|processes|fields)|affected_rows|result|real_escape_string|\n get_(client|host|proto|server)_info\n)\\b", + "name": "support.function.mysql.php" + }, + { + "match": + "(?xi)\\b\nmysqli_(\n ssl_set|store_result|stat|send_(query|long_data)|set_(charset|opt|local_infile_(default|handler))|\n stmt_(store_result|send_long_data|next_result|close|init|data_seek|prepare|execute|fetch|free_result|\n attr_(get|set)|result_metadata|reset|get_(result|warnings)|more_results|bind_(param|result))|\n select_db|slave_query|savepoint|next_result|change_user|character_set_name|connect|commit|\n client_encoding|close|thread_safe|init|options|(enable|disable)_(reads_from_master|rpl_parse)|\n dump_debug_info|debug|data_seek|use_result|ping|poll|param_count|prepare|escape_string|execute|\n embedded_server_(start|end)|kill|query|field_seek|free_result|autocommit|rollback|report|refresh|\n fetch(_(object|fields|field(_direct)?|assoc|all|array|row))?|rpl_(parse_enabled|probe|query_type)|\n release_savepoint|reap_async_query|real_(connect|escape_string|query)|more_results|multi_query|\n get_(charset|connection_stats|client_(stats|info|version)|cache_stats|warnings|links_stats|metadata)|\n master_query|bind_(param|result)|begin_transaction\n)\\b", + "name": "support.function.mysqli.php" + }, + { + "match": "(?i)\\bmysqlnd_memcache_(set|get_config)\\b", + "name": "support.function.mysqlnd-memcache.php" + }, + { + "match": + "(?i)\\bmysqlnd_ms_(set_(user_pick_server|qos)|dump_servers|query_is_select|fabric_select_(shard|global)|get_(stats|last_(used_connection|gtid))|xa_(commit|rollback|gc|begin)|match_wild)\\b", + "name": "support.function.mysqlnd-ms.php" + }, + { + "match": + "(?i)\\bmysqlnd_qc_(set_(storage_handler|cache_condition|is_select|user_handlers)|clear_cache|get_(normalized_query_trace_log|core_stats|cache_info|query_trace_log|available_handlers))\\b", + "name": "support.function.mysqlnd-qc.php" + }, + { + "match": + "(?i)\\bmysqlnd_uh_(set_(statement|connection)_proxy|convert_to_mysqlnd)\\b", + "name": "support.function.mysqlnd-uh.php" + }, + { + "match": + "(?xi)\\b\n(\n syslog|socket_(set_(blocking|timeout)|get_status)|set(raw)?cookie|http_response_code|openlog|\n headers_(list|sent)|header(_(register_callback|remove))?|checkdnsrr|closelog|inet_(ntop|pton)|ip2long|\n openlog|dns_(check_record|get_(record|mx))|define_syslog_variables|(p)?fsockopen|long2ip|\n get(servby(name|port)|host(name|by(name(l)?|addr))|protoby(name|number)|mxrr)\n)\\b", + "name": "support.function.network.php" + }, + { + "match": "(?i)\\bnsapi_(virtual|response_headers|request_headers)\\b", + "name": "support.function.nsapi.php" + }, + { + "match": + "(?xi)\\b\n(\n oci(statementtype|setprefetch|serverversion|savelob(file)?|numcols|new(collection|cursor|descriptor)|nlogon|\n column(scale|size|name|type(raw)?|isnull|precision)|coll(size|trim|assign(elem)?|append|getelem|max)|commit|\n closelob|cancel|internaldebug|definebyname|plogon|parse|error|execute|fetch(statement|into)?|\n free(statement|collection|cursor|desc)|write(temporarylob|lobtofile)|loadlob|log(on|off)|rowcount|rollback|\n result|bindbyname)|\n oci_(statement_type|set_(client_(info|identifier)|prefetch|edition|action|module_name)|server_version|\n num_(fields|rows)|new_(connect|collection|cursor|descriptor)|connect|commit|client_version|close|cancel|\n internal_debug|define_by_name|pconnect|password_change|parse|error|execute|bind_(array_)?by_name|\n field_(scale|size|name|type(_raw)?|is_null|precision)|fetch(_(object|assoc|all|array|row))?|\n free_(statement|descriptor)|lob_(copy|is_equal)|rollback|result|get_implicit_resultset)\n)\\b", + "name": "support.function.oci8.php" + }, + { + "match": + "(?i)\\bopcache_(compile_file|invalidate|reset|get_(status|configuration))\\b", + "name": "support.function.opcache.php" + }, + { + "match": + "(?xi)\\b\nopenssl_(\n sign|spki_(new|export(_challenge)?|verify)|seal|csr_(sign|new|export(_to_file)?|get_(subject|public_key))|\n cipher_iv_length|open|dh_compute_key|digest|decrypt|public_(decrypt|encrypt)|encrypt|error_string|\n pkcs12_(export(_to_file)?|read)|pkcs7_(sign|decrypt|encrypt|verify)|verify|free_key|random_pseudo_bytes|\n pkey_(new|export(_to_file)?|free|get_(details|public|private))|private_(decrypt|encrypt)|pbkdf2|\n get_((cipher|md)_methods|cert_locations|(public|private)key)|\n x509_(check_private_key|checkpurpose|parse|export(_to_file)?|fingerprint|free|read)\n)\\b", + "name": "support.function.openssl.php" + }, + { + "match": + "(?xi)\\b\n(\n output_(add_rewrite_var|reset_rewrite_vars)|flush|\n ob_(start|clean|implicit_flush|end_(clean|flush)|flush|list_handlers|gzhandler|\n get_(status|contents|clean|flush|length|level))\n)\\b", + "name": "support.function.output.php" + }, + { + "match": "(?i)\\bpassword_(hash|needs_rehash|verify|get_info)\\b", + "name": "support.function.password.php" + }, + { + "match": + "(?xi)\\b\npcntl_(\n strerror|signal(_dispatch)?|sig(timedwait|procmask|waitinfo)|setpriority|errno|exec|fork|\n w(stopsig|termsig|if(stopped|signaled|exited))|wait(pid)?|alarm|getpriority|get_last_error\n)\\b", + "name": "support.function.pcntl.php" + }, + { + "match": + "(?xi)\\b\npg_(\n socket|send_(prepare|execute|query(_params)?)|set_(client_encoding|error_verbosity)|select|host|\n num_(fields|rows)|consume_input|connection_(status|reset|busy)|connect(_poll)?|convert|copy_(from|to)|\n client_encoding|close|cancel_query|tty|transaction_status|trace|insert|options|delete|dbname|untrace|\n unescape_bytea|update|pconnect|ping|port|put_line|parameter_status|prepare|version|query(_params)?|\n escape_(string|identifier|literal|bytea)|end_copy|execute|flush|free_result|last_(notice|error|oid)|\n field_(size|num|name|type(_oid)?|table|is_null|prtlen)|affected_rows|result_(status|seek|error(_field)?)|\n fetch_(object|assoc|all(_columns)?|array|row|result)|get_(notify|pid|result)|meta_data|\n lo_(seek|close|create|tell|truncate|import|open|unlink|export|write|read(_all)?)|\n)\\b", + "name": "support.function.pgsql.php" + }, + { + "match": + "(?i)\\b(virtual|getallheaders|apache_((get|set)env|note|child_terminate|lookup_uri|response_headers|reset_timeout|request_headers|get_(version|modules)))\\b", + "name": "support.function.php_apache.php" + }, + { + "match": "(?i)\\bdom_import_simplexml\\b", + "name": "support.function.php_dom.php" + }, + { + "match": + "(?xi)\\b\nftp_(\n ssl_connect|systype|site|size|set_option|nlist|nb_(continue|f?(put|get))|ch(dir|mod)|connect|cdup|close|\n delete|put|pwd|pasv|exec|quit|f(put|get)|login|alloc|rename|raw(list)?|rmdir|get(_option)?|mdtm|mkdir\n)\\b", + "name": "support.function.php_ftp.php" + }, + { + "match": + "(?xi)\\b\nimap_(\n (create|delete|list|rename|scan)(mailbox)?|status|sort|subscribe|set_quota|set(flag_full|acl)|search|savebody|\n num_(recent|msg)|check|close|clearflag_full|thread|timeout|open|header(info)?|headers|append|alerts|reopen|\n 8bit|unsubscribe|undelete|utf7_(decode|encode)|utf8|uid|ping|errors|expunge|qprint|gc|\n fetch(structure|header|text|mime|body)|fetch_overview|lsub|list(scan|subscribed)|last_error|\n rfc822_(parse_(headers|adrlist)|write_address)|get(subscribed|acl|mailboxes)|get_quota(root)?|\n msgno|mime_header_decode|mail_(copy|compose|move)|mail|mailboxmsginfo|binary|body(struct)?|base64\n)\\b", + "name": "support.function.php_imap.php" + }, + { + "match": + "(?xi)\\b\nmssql_(\n select_db|num_(fields|rows)|next_result|connect|close|init|data_seek|pconnect|execute|query|\n field_(seek|name|type|length)|fetch_(object|field|assoc|array|row|batch)|free_(statement|result)|\n rows_affected|result|guid_string|get_last_message|min_(error|message)_severity|bind\n)\\b", + "name": "support.function.php_mssql.php" + }, + { + "match": + "(?xi)\\b\nodbc_(\n statistics|specialcolumns|setoption|num_(fields|rows)|next_result|connect|columns|columnprivileges|commit|\n cursor|close(_all)?|tables|tableprivileges|do|data_source|pconnect|primarykeys|procedures|procedurecolumns|\n prepare|error(msg)?|exec(ute)?|field_(scale|num|name|type|precision|len)|foreignkeys|free_result|\n fetch_(into|object|array|row)|longreadlen|autocommit|rollback|result(_all)?|gettypeinfo|binmode\n)\\b", + "name": "support.function.php_odbc.php" + }, + { + "match": + "(?i)\\bpreg_(split|quote|filter|last_error|replace(_callback)?|grep|match(_all)?)\\b", + "name": "support.function.php_pcre.php" + }, + { + "match": + "(?i)\\b(spl_(classes|object_hash|autoload(_(call|unregister|extensions|functions|register))?)|class_(implements|uses|parents)|iterator_(count|to_array|apply))\\b", + "name": "support.function.php_spl.php" + }, + { + "match": + "(?i)\\bzip_(close|open|entry_(name|compressionmethod|compressedsize|close|open|filesize|read)|read)\\b", + "name": "support.function.php_zip.php" + }, + { + "match": + "(?xi)\\b\nposix_(\n strerror|set(s|e?u|[ep]?g)id|ctermid|ttyname|times|isatty|initgroups|uname|errno|kill|access|\n get(sid|cwd|uid|pid|ppid|pwnam|pwuid|pgid|pgrp|euid|egid|login|rlimit|gid|grnam|groups|grgid)|\n get_last_error|mknod|mkfifo\n)\\b", + "name": "support.function.posix.php" + }, + { + "match": "(?i)\\bset(thread|proc)title\\b", + "name": "support.function.proctitle.php" + }, + { + "match": + "(?xi)\\b\npspell_(\n store_replacement|suggest|save_wordlist|new(_(config|personal))?|check|clear_session|\n config_(save_repl|create|ignore|(data|dict)_dir|personal|runtogether|repl|mode)|add_to_(session|personal)\n)\\b", + "name": "support.function.pspell.php" + }, + { + "match": + "(?i)\\breadline(_(completion_function|clear_history|callback_(handler_(install|remove)|read_char)|info|on_new_line|write_history|list_history|add_history|redisplay|read_history))?\\b", + "name": "support.function.readline.php" + }, + { + "match": "(?i)\\brecode(_(string|file))?\\b", + "name": "support.function.recode.php" + }, + { + "match": + "(?i)\\brrd(c_disconnect|_(create|tune|info|update|error|version|first|fetch|last(update)?|restore|graph|xport))\\b", + "name": "support.function.rrd.php" + }, + { + "match": + "(?xi)\\b\n(\n shm_((get|has|remove|put)_var|detach|attach|remove)|sem_(acquire|release|remove|get)|ftok|\n msg_((get|remove|set|stat)_queue|send|queue_exists|receive)\n)\\b", + "name": "support.function.sem.php" + }, + { + "match": + "(?xi)\\b\nsession_(\n status|start|set_(save_handler|cookie_params)|save_path|name|commit|cache_(expire|limiter)|\n is_registered|id|destroy|decode|unset|unregister|encode|write_close|abort|reset|register(_shutdown)?|\n regenerate_id|get_cookie_params|module_name\n)\\b", + "name": "support.function.session.php" + }, + { + "match": "(?i)\\bshmop_(size|close|open|delete|write|read)\\b", + "name": "support.function.shmop.php" + }, + { + "match": "(?i)\\bsimplexml_(import_dom|load_(string|file))\\b", + "name": "support.function.simplexml.php" + }, + { + "match": + "(?xi)\\b\n(\n snmp(walk(oid)?|realwalk|get(next)?|set)|\n snmp_(set_(valueretrieval|quick_print|enum_print|oid_(numeric_print|output_format))|read_mib|\n get_(valueretrieval|quick_print))|\n snmp[23]_(set|walk|real_walk|get(next)?)\n)\\b", + "name": "support.function.snmp.php" + }, + { + "match": "(?i)\\b(is_soap_fault|use_soap_error_handler)\\b", + "name": "support.function.soap.php" + }, + { + "match": + "(?xi)\\b\nsocket_(\n shutdown|strerror|send(to|msg)?|set_((non)?block|option)|select|connect|close|clear_error|bind|\n create(_(pair|listen))?|cmsg_space|import_stream|write|listen|last_error|accept|recv(from|msg)?|\n read|get(peer|sock)name|get_option\n)\\b", + "name": "support.function.sockets.php" + }, + { + "match": + "(?xi)\\b\nsqlite_(\n single_query|seek|has_(more|prev)|num_(fields|rows)|next|changes|column|current|close|\n create_(aggregate|function)|open|unbuffered_query|udf_(decode|encode)_binary|popen|prev|\n escape_string|error_string|exec|valid|key|query|field_name|factory|\n fetch_(string|single|column_types|object|all|array)|lib(encoding|version)|\n last_(insert_rowid|error)|array_query|rewind|busy_timeout\n)\\b", + "name": "support.function.sqlite.php" + }, + { + "match": + "(?xi)\\b\nsqlsrv_(\n send_stream_data|server_info|has_rows|num_(fields|rows)|next_result|connect|configure|commit|\n client_info|close|cancel|prepare|errors|execute|query|field_metadata|fetch(_(array|object))?|\n free_stmt|rows_affected|rollback|get_(config|field)|begin_transaction\n)\\b", + "name": "support.function.sqlsrv.php" + }, + { + "match": + "(?xi)\\b\nstats_(\n harmonic_mean|covariance|standard_deviation|skew|\n cdf_(noncentral_(chisquare|f)|negative_binomial|chisquare|cauchy|t|uniform|poisson|exponential|f|weibull|\n logistic|laplace|gamma|binomial|beta)|\n stat_(noncentral_t|correlation|innerproduct|independent_t|powersum|percentile|paired_t|gennch|binomial_coef)|\n dens_(normal|negative_binomial|chisquare|cauchy|t|pmf_(hypergeometric|poisson|binomial)|exponential|f|\n weibull|logistic|laplace|gamma|beta)|\n den_uniform|variance|kurtosis|absolute_deviation|\n rand_(setall|phrase_to_seeds|ranf|get_seeds|\n gen_(noncentral_[ft]|noncenral_chisquare|normal|chisquare|t|int|\n i(uniform|poisson|binomial(_negative)?)|exponential|f(uniform)?|gamma|beta))\n)\\b", + "name": "support.function.stats.php" + }, + { + "match": + "(?xi)\\b\n(\n set_socket_blocking|\n stream_(socket_(shutdown|sendto|server|client|pair|enable_crypto|accept|recvfrom|get_name)|\n set_(chunk_size|timeout|(read|write)_buffer|blocking)|select|notification_callback|supports_lock|\n context_(set_(option|default|params)|create|get_(options|default|params))|copy_to_stream|is_local|\n encoding|filter_(append|prepend|register|remove)|wrapper_((un)?register|restore)|\n resolve_include_path|register_wrapper|get_(contents|transports|filters|wrappers|line|meta_data)|\n bucket_(new|prepend|append|make_writeable)\n )\n)\\b", + "name": "support.function.streamsfuncs.php" + }, + { + "match": + "(?xi)\\b\n(\n money_format|md5(_file)?|metaphone|bin2hex|sscanf|sha1(_file)?|\n str(str|c?spn|n(at)?(case)?cmp|chr|coll|(case)?cmp|to(upper|lower)|tok|tr|istr|pos|pbrk|len|rchr|ri?pos|rev)|\n str_(getcsv|ireplace|pad|repeat|replace|rot13|shuffle|split|word_count)|\n strip(c?slashes|os)|strip_tags|similar_text|soundex|substr(_(count|compare|replace))?|setlocale|\n html(specialchars(_decode)?|entities)|html_entity_decode|hex2bin|hebrev(c)?|number_format|nl2br|nl_langinfo|\n chop|chunk_split|chr|convert_(cyr_string|uu(decode|encode))|count_chars|crypt|crc32|trim|implode|ord|\n uc(first|words)|join|parse_str|print(f)?|echo|explode|v?[fs]?printf|quoted_printable_(decode|encode)|\n quotemeta|wordwrap|lcfirst|[lr]trim|localeconv|levenshtein|addc?slashes|get_html_translation_table\n)\\b", + "name": "support.function.string.php" + }, + { + "match": + "(?xi)\\b\nsybase_(\n set_message_handler|select_db|num_(fields|rows)|connect|close|deadlock_retry_count|data_seek|\n unbuffered_query|pconnect|query|field_seek|fetch_(object|field|assoc|array|row)|free_result|\n affected_rows|result|get_last_message|min_(client|error|message|server)_severity\n)\\b", + "name": "support.function.sybase.php" + }, + { + "match": "(?i)\\b(taint|is_tainted|untaint)\\b", + "name": "support.function.taint.php" + }, + { + "match": + "(?xi)\\b\n(\n tidy_((get|set)opt|set_encoding|save_config|config_count|clean_repair|is_(xhtml|xml)|diagnose|\n (access|error|warning)_count|load_config|reset_config|(parse|repair)_(string|file)|\n get_(status|html(_ver)?|head|config|output|opt_doc|root|release|body))|\n ob_tidyhandler\n)\\b", + "name": "support.function.tidy.php" + }, + { + "match": "(?i)\\btoken_(name|get_all)\\b", + "name": "support.function.tokenizer.php" + }, + { + "match": + "(?xi)\\b\ntrader_(\n stoch(f|r|rsi)?|stddev|sin(h)?|sum|sub|set_(compat|unstable_period)|sqrt|sar(ext)?|sma|\n ht_(sine|trend(line|mode)|dc(period|phase)|phasor)|natr|cci|cos(h)?|correl|\n cdl(shootingstar|shortline|sticksandwich|stalledpattern|spinningtop|separatinglines|\n hikkake(mod)?|highwave|homingpigeon|hangingman|harami(cross)?|hammer|concealbabyswall|\n counterattack|closingmarubozu|thrusting|tasukigap|takuri|tristar|inneck|invertedhammer|\n identical3crows|2crows|onneck|doji(star)?|darkcloudcover|dragonflydoji|unique3river|\n upsidegap2crows|3(starsinsouth|inside|outside|whitesoldiers|linestrike|blackcrows)|\n piercing|engulfing|evening(doji)?star|kicking(bylength)?|longline|longleggeddoji|\n ladderbottom|advanceblock|abandonedbaby|risefall3methods|rickshawman|gapsidesidewhite|\n gravestonedoji|xsidegap3methods|morning(doji)?star|mathold|matchinglow|marubozu|\n belthold|breakaway)|\n ceil|cmo|tsf|typprice|t3|tema|tan(h)?|trix|trima|trange|obv|div|dema|dx|ultosc|ppo|\n plus_d[im]|errno|exp|ema|var|kama|floor|wclprice|willr|wma|ln|log10|bop|beta|bbands|\n linearreg(_(slope|intercept|angle))?|asin|acos|atan|atr|adosc|ad|add|adx(r)?|apo|avgprice|\n aroon(osc)?|rsi|roc|rocp|rocr(100)?|get_(compat|unstable_period)|min(index)?|minus_d[im]|\n minmax(index)?|mid(point|price)|mom|mult|medprice|mfi|macd(ext|fix)?|mavp|max(index)?|ma(ma)?\n)\\b", + "name": "support.function.trader.php" + }, + { + "match": + "(?i)\\buopz_(copy|compose|implement|overload|delete|undefine|extend|function|flags|restore|rename|redefine|backup)\\b", + "name": "support.function.uopz.php" + }, + { + "match": + "(?i)\\b(http_build_query|(raw)?url(decode|encode)|parse_url|get_(headers|meta_tags)|base64_(decode|encode))\\b", + "name": "support.function.url.php" + }, + { + "match": + "(?xi)\\b\n(\n strval|settype|serialize|(bool|double|float)val|debug_zval_dump|intval|import_request_variables|isset|\n is_(scalar|string|null|numeric|callable|int(eger)?|object|double|float|long|array|resource|real|bool)|\n unset|unserialize|print_r|empty|var_(dump|export)|gettype|get_(defined_vars|resource_type)\n)\\b", + "name": "support.function.var.php" + }, + { + "match": + "(?i)\\bwddx_(serialize_(value|vars)|deserialize|packet_(start|end)|add_vars)\\b", + "name": "support.function.wddx.php" + }, + { + "match": "(?i)\\bxhprof_(sample_)?(disable|enable)\\b", + "name": "support.function.xhprof.php" + }, + { + "match": + "(?xi)\n\\b\n(\n utf8_(decode|encode)|\n xml_(set_((notation|(end|start)_namespace|unparsed_entity)_decl_handler|\n (character_data|default|element|external_entity_ref|processing_instruction)_handler|object)|\n parse(_into_struct)?|parser_((get|set)_option|create(_ns)?|free)|error_string|\n get_(current_((column|line)_number|byte_index)|error_code))\n)\\b", + "name": "support.function.xml.php" + }, + { + "match": + "(?xi)\\b\nxmlrpc_(\n server_(call_method|create|destroy|add_introspection_data|register_(introspection_callback|method))|\n is_fault|decode(_request)?|parse_method_descriptions|encode(_request)?|(get|set)_type\n)\\b", + "name": "support.function.xmlrpc.php" + }, + { + "match": + "(?xi)\\b\nxmlwriter_(\n (end|start|write)_(comment|cdata|dtd(_(attlist|entity|element))?|document|pi|attribute|element)|\n (start|write)_(attribute|element)_ns|write_raw|set_indent(_string)?|text|output_memory|open_(memory|uri)|\n full_end_element|flush|\n)\\b", + "name": "support.function.xmlwriter.php" + }, + { + "match": + "(?xi)\\b\n(\n zlib_(decode|encode|get_coding_type)|readgzfile|\n gz(seek|compress|close|tell|inflate|open|decode|deflate|uncompress|puts|passthru|encode|eof|file|\n write|rewind|read|getc|getss?)\n)\\b", + "name": "support.function.zlib.php" + }, + { + "match": "(?i)\\bis_int(eger)?\\b", + "name": "support.function.alias.php" + } + ] + }, + "switch_statement": { + "patterns": [ + { + "match": "\\s+(?=switch\\b)" + }, + { + "begin": "\\bswitch\\b(?!\\s*\\(.*\\)\\s*:)", + "beginCaptures": { + "0": { + "name": "keyword.control.switch.php" + } + }, + "end": "}|(?=\\?>)", + "endCaptures": { + "0": { + "name": + "punctuation.definition.section.switch-block.end.bracket.curly.php" + } + }, + "name": "meta.switch-statement.php", + "patterns": [ + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": + "punctuation.definition.switch-expression.begin.bracket.round.php" + } + }, + "end": "\\)|(?=\\?>)", + "endCaptures": { + "0": { + "name": + "punctuation.definition.switch-expression.end.bracket.round.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": + "punctuation.definition.section.switch-block.begin.bracket.curly.php" + } + }, + "end": "(?=}|\\?>)", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + } + ] + }, + "use-inner": { + "patterns": [ + { + "include": "#comments" + }, + { + "begin": "(?i)\\b(as)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.other.use-as.php" + } + }, + "end": "(?i)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "endCaptures": { + "0": { + "name": "entity.other.alias.php" + } + } + }, + { + "include": "#class-name" + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.php" + } + ] + }, + "var_basic": { + "patterns": [ + { + "match": "(?i)(\\$+)[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*", + "name": "variable.other.php", + "captures": { + "1": { + "name": "punctuation.definition.variable.php" + } + } + } + ] + }, + "var_global": { + "captures": { + "1": { + "name": "punctuation.definition.variable.php" + } + }, + "match": "(\\$)((_(COOKIE|FILES|GET|POST|REQUEST))|arg(v|c))\\b", + "name": "variable.other.global.php" + }, + "var_global_safer": { + "captures": { + "1": { + "name": "punctuation.definition.variable.php" + } + }, + "match": "(\\$)((GLOBALS|_(ENV|SERVER|SESSION)))", + "name": "variable.other.global.safer.php" + }, + "var_language": { + "match": "(\\$)this\\b", + "name": "variable.language.this.php", + "captures": { + "1": { + "name": "punctuation.definition.variable.php" + } + } + }, + "variable-name": { + "patterns": [ + { + "include": "#var_global" + }, + { + "include": "#var_global_safer" + }, + { + "captures": { + "1": { + "name": "variable.other.php" + }, + "2": { + "name": "punctuation.definition.variable.php" + }, + "4": { + "name": "keyword.operator.class.php" + }, + "5": { + "name": "variable.other.property.php" + }, + "6": { + "name": "punctuation.section.array.begin.php" + }, + "7": { + "name": "constant.numeric.index.php" + }, + "8": { + "name": "variable.other.index.php" + }, + "9": { + "name": "punctuation.definition.variable.php" + }, + "10": { + "name": "string.unquoted.index.php" + }, + "11": { + "name": "punctuation.section.array.end.php" + } + }, + "match": + "(?xi)\n((\\$)(?<name>[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*))\n(?:\n (->)(\\g<name>)\n |\n (\\[)(?:(\\d+)|((\\$)\\g<name>)|([a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*))(\\])\n)?" + }, + { + "captures": { + "1": { + "name": "variable.other.php" + }, + "2": { + "name": "punctuation.definition.variable.php" + }, + "4": { + "name": "punctuation.definition.variable.php" + } + }, + "match": + "(?i)((\\${)(?<name>[a-z_\\x{7f}-\\x{7fffffff}][a-z0-9_\\x{7f}-\\x{7fffffff}]*)(}))" + } + ] + }, + "variables": { + "patterns": [ + { + "include": "#var_language" + }, + { + "include": "#var_global" + }, + { + "include": "#var_global_safer" + }, + { + "include": "#var_basic" + }, + { + "begin": "\\${(?=.*?})", + "beginCaptures": { + "0": { + "name": "punctuation.definition.variable.php" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.definition.variable.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "ternary_shorthand": { + "match": "\\?:", + "name": "keyword.operator.ternary.php" + }, + "ternary_expression": { + "begin": "\\?", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.php" + } + }, + "end": ":", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.php" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + "null_coalescing": { + "match": "\\?\\?", + "name": "keyword.operator.null-coalescing.php" + } + } +} diff --git a/extensions/python/syntaxes/python.tmLanguage.json b/extensions/python/syntaxes/python.tmLanguage.json new file mode 100755 index 0000000000..ea5f6e0b8b --- /dev/null +++ b/extensions/python/syntaxes/python.tmLanguage.json @@ -0,0 +1,5368 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/MagicStack/MagicPython/blob/master/grammars/MagicPython.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/MagicStack/MagicPython/commit/b453f26ed856c9b16a053517c41207e3a72cc7d5", + "name": "MagicPython", + "scopeName": "source.python", + "patterns": [ + { + "include": "#statement" + }, + { + "include": "#expression" + } + ], + "repository": { + "impossible": { + "comment": + "This is a special rule that should be used where no match is desired. It is not a good idea to match something like '1{0}' because in some cases that can result in infinite loops in token generation. So the rule instead matches and impossible expression to allow a match to fail and move to the next token.", + "match": "$.^" + }, + "statement": { + "patterns": [ + { + "include": "#import" + }, + { + "include": "#class-declaration" + }, + { + "include": "#function-declaration" + }, + { + "include": "#statement-keyword" + }, + { + "include": "#assignment-operator" + }, + { + "include": "#decorator" + }, + { + "include": "#docstring-statement" + }, + { + "include": "#semicolon" + } + ] + }, + "semicolon": { + "patterns": [ + { + "name": "invalid.deprecated.semicolon.python", + "match": "\\;$" + } + ] + }, + "comments": { + "patterns": [ + { + "name": "comment.line.number-sign.python", + "contentName": "meta.typehint.comment.python", + "begin": + "(?x)\n (?:\n \\# \\s* (type:)\n \\s*+ (?# we want `\\s*+` which is possessive quantifier since\n we do not actually want to backtrack when matching\n whitespace here)\n (?! $ | \\#)\n )\n", + "end": "(?:$|(?=\\#))", + "beginCaptures": { + "0": { + "name": "meta.typehint.comment.python" + }, + "1": { + "name": "comment.typehint.directive.notation.python" + } + }, + "patterns": [ + { + "name": "comment.typehint.ignore.notation.python", + "match": "(?x)\n \\G ignore\n (?= \\s* (?: $ | \\#))\n" + }, + { + "name": "comment.typehint.type.notation.python", + "match": + "(?x)\n (?<!\\.)\\b(\n bool | bytes | float | int | object | str\n | List | Dict | Iterable | Sequence | Set\n | FrozenSet | Callable | Union | Tuple\n | Any | None\n )\\b\n" + }, + { + "name": "comment.typehint.punctuation.notation.python", + "match": "([\\[\\]\\(\\),\\.\\=\\*]|(->))" + }, + { + "name": "comment.typehint.variable.notation.python", + "match": "([[:alpha:]_]\\w*)" + } + ] + }, + { + "include": "#comments-base" + } + ] + }, + "docstring-statement": { + "begin": "^(?=\\s*[rR]?(\\'\\'\\'|\\\"\\\"\\\"|\\'|\\\"))", + "end": "(?<=\\'\\'\\'|\\\"\\\"\\\"|\\'|\\\")", + "patterns": [ + { + "include": "#docstring" + } + ] + }, + "docstring": { + "patterns": [ + { + "name": "string.quoted.docstring.multi.python", + "begin": "(\\'\\'\\'|\\\"\\\"\\\")", + "end": "(\\1)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + } + }, + "patterns": [ + { + "include": "#docstring-prompt" + }, + { + "include": "#codetags" + }, + { + "include": "#docstring-guts-unicode" + } + ] + }, + { + "name": "string.quoted.docstring.raw.multi.python", + "begin": "([rR])(\\'\\'\\'|\\\"\\\"\\\")", + "end": "(\\2)", + "beginCaptures": { + "1": { + "name": "storage.type.string.python" + }, + "2": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + } + }, + "patterns": [ + { + "include": "#string-consume-escape" + }, + { + "include": "#docstring-prompt" + }, + { + "include": "#codetags" + } + ] + }, + { + "name": "string.quoted.docstring.single.python", + "begin": "(\\'|\\\")", + "end": "(\\1)|((?<!\\\\)\\n)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#codetags" + }, + { + "include": "#docstring-guts-unicode" + } + ] + }, + { + "name": "string.quoted.docstring.raw.single.python", + "begin": "([rR])(\\'|\\\")", + "end": "(\\2)|((?<!\\\\)\\n)", + "beginCaptures": { + "1": { + "name": "storage.type.string.python" + }, + "2": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-consume-escape" + }, + { + "include": "#codetags" + } + ] + } + ] + }, + "docstring-guts-unicode": { + "patterns": [ + { + "include": "#escape-sequence-unicode" + }, + { + "include": "#escape-sequence" + }, + { + "include": "#string-line-continuation" + } + ] + }, + "docstring-prompt": { + "match": + "(?x)\n (?:\n (?:^|\\G) \\s* (?# '\\G' is necessary for ST)\n ((?:>>>|\\.\\.\\.) \\s) (?=\\s*\\S)\n )\n", + "captures": { + "1": { + "name": "keyword.control.flow.python" + } + } + }, + "statement-keyword": { + "patterns": [ + { + "name": "storage.type.function.python", + "match": "\\b((async\\s+)?\\s*def)\\b" + }, + { + "name": "keyword.control.flow.python", + "match": + "(?x)\n \\b(?<!\\.)(\n as | async | continue | del | assert | break | finally | for\n | from | elif | else | if | except | pass | raise\n | return | try | while | with\n )\\b\n" + }, + { + "name": "storage.modifier.declaration.python", + "match": "(?x)\n \\b(?<!\\.)(\n global | nonlocal\n )\\b\n" + }, + { + "name": "storage.type.class.python", + "match": "\\b(?<!\\.)(class)\\b" + } + ] + }, + "expression-bare": { + "comment": "valid Python expressions w/o comments and line continuation", + "patterns": [ + { + "include": "#backticks" + }, + { + "include": "#illegal-anno" + }, + { + "include": "#literal" + }, + { + "include": "#regexp" + }, + { + "include": "#string" + }, + { + "include": "#lambda" + }, + { + "include": "#illegal-operator" + }, + { + "include": "#operator" + }, + { + "include": "#curly-braces" + }, + { + "include": "#item-access" + }, + { + "include": "#list" + }, + { + "include": "#round-braces" + }, + { + "include": "#function-call" + }, + { + "include": "#builtin-functions" + }, + { + "include": "#builtin-types" + }, + { + "include": "#builtin-exceptions" + }, + { + "include": "#magic-names" + }, + { + "include": "#special-names" + }, + { + "include": "#illegal-names" + }, + { + "include": "#special-variables" + }, + { + "include": "#ellipsis" + }, + { + "include": "#punctuation" + }, + { + "include": "#line-continuation" + } + ] + }, + "expression-base": { + "comment": "valid Python expressions with comments and line continuation", + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#expression-bare" + }, + { + "include": "#line-continuation" + } + ] + }, + "expression": { + "comment": "All valid Python expressions", + "patterns": [ + { + "include": "#expression-base" + }, + { + "include": "#member-access" + }, + { + "comment": "Tokenize identifiers to help linters", + "match": "(?x) \\b ([[:alpha:]_]\\w*) \\b" + } + ] + }, + "member-access": { + "begin": "(\\.)\\s*(?!\\.)", + "end": + "(?x)\n # stop when you've just read non-whitespace followed by non-word\n # i.e. when finished reading an identifier or function call\n (?<=\\S)(?=\\W) |\n # stop when seeing the start of something that's not a word,\n # i.e. when seeing a non-identifier\n (^|(?<=\\s))(?=[^\\\\\\w\\s]) |\n $\n", + "beginCaptures": { + "1": { + "name": "punctuation.separator.period.python" + } + }, + "patterns": [ + { + "include": "#function-call" + }, + { + "include": "#member-access-base" + } + ] + }, + "member-access-base": { + "patterns": [ + { + "include": "#magic-names" + }, + { + "include": "#illegal-names" + }, + { + "include": "#illegal-object-name" + }, + { + "include": "#special-names" + }, + { + "include": "#line-continuation" + }, + { + "include": "#item-access" + } + ] + }, + "special-names": { + "name": "constant.other.caps.python", + "match": + "(?x)\n \\b\n # we want to see \"enough\", meaning 2 or more upper-case\n # letters in the beginning of the constant\n #\n # for more details refer to:\n # https://github.com/MagicStack/MagicPython/issues/42\n (\n _* [[:upper:]] [_\\d]* [[:upper:]]\n )\n [[:upper:]\\d]* (_\\w*)?\n \\b\n" + }, + "curly-braces": { + "begin": "\\{", + "end": "\\}", + "beginCaptures": { + "0": { + "name": "punctuation.definition.dict.begin.python" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.dict.end.python" + } + }, + "patterns": [ + { + "name": "punctuation.separator.dict.python", + "match": ":" + }, + { + "include": "#expression" + } + ] + }, + "list": { + "begin": "\\[", + "end": "\\]", + "beginCaptures": { + "0": { + "name": "punctuation.definition.list.begin.python" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.list.end.python" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "round-braces": { + "begin": "\\(", + "end": "\\)", + "beginCaptures": { + "0": { + "name": "punctuation.parenthesis.begin.python" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.parenthesis.end.python" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "line-continuation": { + "patterns": [ + { + "match": "(\\\\)\\s*(\\S.*$\\n?)", + "captures": { + "1": { + "name": "punctuation.separator.continuation.line.python" + }, + "2": { + "name": "invalid.illegal.line.continuation.python" + } + } + }, + { + "begin": "(\\\\)\\s*$\\n?", + "end": + "(?x)\n (?=^\\s*$)\n |\n (?! (\\s* [rR]? (\\'\\'\\'|\\\"\\\"\\\"|\\'|\\\"))\n |\n (\\G $) (?# '\\G' is necessary for ST)\n )\n", + "beginCaptures": { + "1": { + "name": "punctuation.separator.continuation.line.python" + } + }, + "patterns": [ + { + "include": "#regexp" + }, + { + "include": "#string" + } + ] + } + ] + }, + "assignment-operator": { + "name": "keyword.operator.assignment.python", + "match": + "(?x)\n <<= | >>= | //= | \\*\\*=\n | \\+= | -= | /= | @=\n | \\*= | %= | ~= | \\^= | &= | \\|=\n | =(?!=)\n" + }, + "operator": { + "match": + "(?x)\n \\b(?<!\\.)\n (?:\n (and | or | not | in | is) (?# 1)\n |\n (for | if | else | await | (?:yield(?:\\s+from)?)) (?# 2)\n )\n (?!\\s*:)\\b\n\n | (<< | >> | & | \\| | \\^ | ~) (?# 3)\n\n | (\\*\\* | \\* | \\+ | - | % | // | / | @) (?# 4)\n\n | (!= | == | >= | <= | < | >) (?# 5)\n", + "captures": { + "1": { + "name": "keyword.operator.logical.python" + }, + "2": { + "name": "keyword.control.flow.python" + }, + "3": { + "name": "keyword.operator.bitwise.python" + }, + "4": { + "name": "keyword.operator.arithmetic.python" + }, + "5": { + "name": "keyword.operator.comparison.python" + } + } + }, + "punctuation": { + "patterns": [ + { + "name": "punctuation.separator.colon.python", + "match": ":" + }, + { + "name": "punctuation.separator.element.python", + "match": "," + } + ] + }, + "literal": { + "patterns": [ + { + "name": "constant.language.python", + "match": "\\b(True|False|None|NotImplemented|Ellipsis)\\b" + }, + { + "include": "#number" + } + ] + }, + "number": { + "name": "constant.numeric.python", + "patterns": [ + { + "include": "#number-float" + }, + { + "include": "#number-dec" + }, + { + "include": "#number-hex" + }, + { + "include": "#number-oct" + }, + { + "include": "#number-bin" + }, + { + "include": "#number-long" + }, + { + "name": "invalid.illegal.name.python", + "match": "\\b[0-9]+\\w+" + } + ] + }, + "number-float": { + "name": "constant.numeric.float.python", + "match": + "(?x)\n (?<! \\w)(?:\n (?:\n \\.[0-9](?: _?[0-9] )*\n |\n [0-9](?: _?[0-9] )* \\. [0-9](?: _?[0-9] )*\n |\n [0-9](?: _?[0-9] )* \\.\n ) (?: [eE][+-]?[0-9](?: _?[0-9] )* )?\n |\n [0-9](?: _?[0-9] )* (?: [eE][+-]?[0-9](?: _?[0-9] )* )\n )([jJ])?\\b\n", + "captures": { + "1": { + "name": "storage.type.imaginary.number.python" + } + } + }, + "number-dec": { + "name": "constant.numeric.dec.python", + "match": + "(?x)\n (?<![\\w\\.])(?:\n [1-9](?: _?[0-9] )*\n |\n 0+\n |\n [0-9](?: _?[0-9] )* ([jJ])\n |\n 0 ([0-9]+)(?![eE\\.])\n )\\b\n", + "captures": { + "1": { + "name": "storage.type.imaginary.number.python" + }, + "2": { + "name": "invalid.illegal.dec.python" + }, + "3": { + "name": "invalid.illegal.dec.python" + } + } + }, + "number-hex": { + "name": "constant.numeric.hex.python", + "match": "(?x)\n (?<![\\w\\.])\n (0[xX]) (_?[0-9a-fA-F])+\n \\b\n", + "captures": { + "1": { + "name": "storage.type.number.python" + } + } + }, + "number-oct": { + "name": "constant.numeric.oct.python", + "match": "(?x)\n (?<![\\w\\.])\n (0[oO]) (_?[0-7])+\n \\b\n", + "captures": { + "1": { + "name": "storage.type.number.python" + } + } + }, + "number-bin": { + "name": "constant.numeric.bin.python", + "match": "(?x)\n (?<![\\w\\.])\n (0[bB]) (_?[01])+\n \\b\n", + "captures": { + "1": { + "name": "storage.type.number.python" + } + } + }, + "number-long": { + "name": "constant.numeric.bin.python", + "comment": "this is to support python2 syntax for long ints", + "match": "(?x)\n (?<![\\w\\.])\n ([1-9][0-9]* | 0) ([lL])\n \\b\n", + "captures": { + "2": { + "name": "storage.type.number.python" + } + } + }, + "regexp": { + "patterns": [ + { + "include": "#regexp-single-three-line" + }, + { + "include": "#regexp-double-three-line" + }, + { + "include": "#regexp-single-one-line" + }, + { + "include": "#regexp-double-one-line" + }, + { + "include": "#fregexp-single-three-line" + }, + { + "include": "#fregexp-double-three-line" + }, + { + "include": "#fregexp-single-one-line" + }, + { + "include": "#fregexp-double-one-line" + } + ] + }, + "string": { + "patterns": [ + { + "include": "#string-quoted-multi-line" + }, + { + "include": "#string-quoted-single-line" + }, + { + "include": "#string-bin-quoted-multi-line" + }, + { + "include": "#string-bin-quoted-single-line" + }, + { + "include": "#string-raw-quoted-multi-line" + }, + { + "include": "#string-raw-quoted-single-line" + }, + { + "include": "#string-raw-bin-quoted-multi-line" + }, + { + "include": "#string-raw-bin-quoted-single-line" + }, + { + "include": "#fstring-fnorm-quoted-multi-line" + }, + { + "include": "#fstring-fnorm-quoted-single-line" + }, + { + "include": "#fstring-normf-quoted-multi-line" + }, + { + "include": "#fstring-normf-quoted-single-line" + }, + { + "include": "#fstring-raw-quoted-multi-line" + }, + { + "include": "#fstring-raw-quoted-single-line" + } + ] + }, + "string-unicode-guts": { + "patterns": [ + { + "include": "#escape-sequence-unicode" + }, + { + "include": "#string-entity" + }, + { + "include": "#string-brace-formatting" + } + ] + }, + "string-consume-escape": { + "match": "\\\\['\"\\n\\\\]" + }, + "string-raw-guts": { + "patterns": [ + { + "include": "#string-consume-escape" + }, + { + "include": "#string-formatting" + }, + { + "include": "#string-brace-formatting" + } + ] + }, + "string-raw-bin-guts": { + "patterns": [ + { + "include": "#string-consume-escape" + }, + { + "include": "#string-formatting" + } + ] + }, + "string-entity": { + "patterns": [ + { + "include": "#escape-sequence" + }, + { + "include": "#string-line-continuation" + }, + { + "include": "#string-formatting" + } + ] + }, + "fstring-guts": { + "patterns": [ + { + "include": "#escape-sequence-unicode" + }, + { + "include": "#escape-sequence" + }, + { + "include": "#string-line-continuation" + }, + { + "include": "#fstring-formatting" + } + ] + }, + "fstring-raw-guts": { + "patterns": [ + { + "include": "#string-consume-escape" + }, + { + "include": "#fstring-formatting" + } + ] + }, + "fstring-illegal-single-brace": { + "comment": "it is illegal to have a multiline brace inside a single-line string", + "begin": "(\\{)(?=[^\\n}]*$\\n?)", + "end": "(\\})|(?=\\n)", + "beginCaptures": { + "1": { + "name": "constant.character.format.placeholder.other.python" + } + }, + "endCaptures": { + "1": { + "name": "constant.character.format.placeholder.other.python" + } + }, + "patterns": [ + { + "include": "#fstring-terminator-single" + }, + { + "include": "#f-expression" + } + ] + }, + "fstring-illegal-multi-brace": { + "patterns": [ + { + "include": "#impossible" + } + ] + }, + "f-expression": { + "comment": "All valid Python expressions, except comments and line cont", + "patterns": [ + { + "include": "#expression-bare" + }, + { + "include": "#member-access" + }, + { + "comment": "Tokenize identifiers to help linters", + "match": "(?x) \\b ([[:alpha:]_]\\w*) \\b" + } + ] + }, + "escape-sequence-unicode": { + "patterns": [ + { + "name": "constant.character.escape.python", + "match": + "(?x)\n \\\\ (\n u[0-9A-Fa-f]{4}\n | U[0-9A-Fa-f]{8}\n | N\\{[\\w\\s]+?\\}\n )\n" + } + ] + }, + "escape-sequence": { + "name": "constant.character.escape.python", + "match": + "(?x)\n \\\\ (\n x[0-9A-Fa-f]{2}\n | [0-7]{1,3}\n | [\\\\\"'abfnrtv]\n )\n" + }, + "string-line-continuation": { + "name": "constant.language.python", + "match": "\\\\$" + }, + "string-formatting": { + "name": "constant.character.format.placeholder.other.python", + "match": + "(?x)\n % (\\([\\w\\s]*\\))?\n [-+#0 ]*\n (\\d+|\\*)? (\\.(\\d+|\\*))?\n ([hlL])?\n [diouxXeEfFgGcrsa%]\n" + }, + "string-brace-formatting": { + "patterns": [ + { + "name": "constant.character.format.placeholder.other.python", + "match": + "(?x)\n (?:\n {{ | }}\n | (?:\n {\n \\w*? (\\.[[:alpha:]_]\\w*? | \\[[^\\]'\"]+\\])*?\n (![rsa])?\n ( : \\w? [<>=^]? [-+ ]? \\#?\n \\d* ,? (\\.\\d+)? [bcdeEfFgGnosxX%]? )?\n })\n )\n", + "captures": { + "2": { + "name": "storage.type.format.python" + }, + "3": { + "name": "storage.type.format.python" + } + } + }, + { + "name": "constant.character.format.placeholder.other.python", + "begin": + "(?x)\n \\{\n \\w*? (\\.[[:alpha:]_]\\w*? | \\[[^\\]'\"]+\\])*?\n (![rsa])?\n (:)\n (?=[^'\"}\\n]*\\})\n", + "end": "\\}", + "beginCaptures": { + "2": { + "name": "storage.type.format.python" + }, + "3": { + "name": "storage.type.format.python" + } + }, + "patterns": [ + { + "match": "(?x) \\{ [^'\"}\\n]*? \\} (?=.*?\\})\n" + } + ] + } + ] + }, + "fstring-formatting": { + "patterns": [ + { + "include": "#fstring-formatting-braces" + }, + { + "include": "#fstring-formatting-singe-brace" + } + ] + }, + "fstring-formatting-singe-brace": { + "name": "invalid.illegal.brace.python", + "match": "(}(?!}))" + }, + "import": { + "comment": "Import statements\n", + "patterns": [ + { + "match": "(?x)\n \\s* \\b(from)\\b \\s*(\\.+)\\s* (import)?\n", + "captures": { + "1": { + "name": "keyword.control.import.python" + }, + "2": { + "name": "punctuation.separator.period.python" + }, + "3": { + "name": "keyword.control.import.python" + } + } + }, + { + "name": "keyword.control.import.python", + "match": "\\b(?<!\\.)import\\b" + } + ] + }, + "class-declaration": { + "patterns": [ + { + "name": "meta.class.python", + "begin": + "(?x)\n \\s*(class)\\s+\n (?=\n [[:alpha:]_]\\w* \\s* (:|\\()\n )\n", + "end": "(:)", + "beginCaptures": { + "1": { + "name": "storage.type.class.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.section.class.begin.python" + } + }, + "patterns": [ + { + "include": "#class-name" + }, + { + "include": "#class-inheritance" + } + ] + } + ] + }, + "class-name": { + "patterns": [ + { + "include": "#illegal-object-name" + }, + { + "include": "#builtin-possible-callables" + }, + { + "name": "entity.name.type.class.python", + "match": "(?x)\n \\b ([[:alpha:]_]\\w*) \\b\n" + } + ] + }, + "class-inheritance": { + "name": "meta.class.inheritance.python", + "begin": "(\\()", + "end": "(\\))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.inheritance.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.inheritance.end.python" + } + }, + "patterns": [ + { + "name": "keyword.operator.unpacking.arguments.python", + "match": "(\\*\\*|\\*)" + }, + { + "name": "punctuation.separator.inheritance.python", + "match": "," + }, + { + "name": "keyword.operator.assignment.python", + "match": "=(?!=)" + }, + { + "name": "support.type.metaclass.python", + "match": "\\bmetaclass\\b" + }, + { + "include": "#illegal-names" + }, + { + "include": "#class-kwarg" + }, + { + "include": "#call-wrapper-inheritance" + }, + { + "include": "#expression-base" + }, + { + "include": "#member-access-class" + }, + { + "include": "#inheritance-identifier" + } + ] + }, + "class-kwarg": { + "match": "(?x)\n \\b ([[:alpha:]_]\\w*) \\s*(=)(?!=)\n", + "captures": { + "1": { + "name": "entity.other.inherited-class.python variable.parameter.class.python" + }, + "2": { + "name": "keyword.operator.assignment.python" + } + } + }, + "inheritance-identifier": { + "match": "(?x)\n \\b ([[:alpha:]_]\\w*) \\b\n", + "captures": { + "1": { + "name": "entity.other.inherited-class.python" + } + } + }, + "member-access-class": { + "begin": "(\\.)\\s*(?!\\.)", + "end": "(?<=\\S)(?=\\W)|$", + "beginCaptures": { + "1": { + "name": "punctuation.separator.period.python" + } + }, + "patterns": [ + { + "include": "#call-wrapper-inheritance" + }, + { + "include": "#member-access-base" + }, + { + "include": "#inheritance-identifier" + } + ] + }, + "lambda": { + "patterns": [ + { + "match": "((?<=\\.)lambda|lambda(?=\\s*[\\.=]))", + "captures": { + "1": { + "name": "keyword.control.flow.python" + } + } + }, + { + "match": "\\b(lambda)\\s*?(?=[,\\n]|$)", + "captures": { + "1": { + "name": "storage.type.function.lambda.python" + } + } + }, + { + "name": "meta.lambda-function.python", + "begin": "(?x)\n \\b (lambda) \\b\n", + "end": "(:)|(\\n)", + "beginCaptures": { + "1": { + "name": "storage.type.function.lambda.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.section.function.lambda.begin.python" + } + }, + "contentName": "meta.function.lambda.parameters.python", + "patterns": [ + { + "name": "keyword.operator.unpacking.parameter.python", + "match": "(\\*\\*|\\*)" + }, + { + "include": "#lambda-nested-incomplete" + }, + { + "include": "#illegal-names" + }, + { + "match": "([[:alpha:]_]\\w*)\\s*(?:(,)|(?=:|$))", + "captures": { + "1": { + "name": "variable.parameter.function.language.python" + }, + "2": { + "name": "punctuation.separator.parameters.python" + } + } + }, + { + "include": "#comments" + }, + { + "include": "#backticks" + }, + { + "include": "#illegal-anno" + }, + { + "include": "#lambda-parameter-with-default" + }, + { + "include": "#line-continuation" + }, + { + "include": "#illegal-operator" + } + ] + } + ] + }, + "lambda-incomplete": { + "name": "storage.type.function.lambda.python", + "match": "\\blambda(?=\\s*[,)])" + }, + "lambda-nested-incomplete": { + "name": "storage.type.function.lambda.python", + "match": "\\blambda(?=\\s*[:,)])" + }, + "lambda-parameter-with-default": { + "begin": "(?x)\n \\b\n ([[:alpha:]_]\\w*) \\s* (=)\n", + "end": "(,)|(?=:|$)", + "beginCaptures": { + "1": { + "name": "variable.parameter.function.language.python" + }, + "2": { + "name": "keyword.operator.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.separator.parameters.python" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-declaration": { + "name": "meta.function.python", + "begin": + "(?x)\n \\s*\n (?:\\b(async) \\s+)? \\b(def)\\s+\n (?=\n [[:alpha:]_][[:word:]]* \\s* \\(\n )\n", + "end": "(:|(?=[#'\"\\n]))", + "beginCaptures": { + "1": { + "name": "storage.type.function.async.python" + }, + "2": { + "name": "storage.type.function.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.section.function.begin.python" + } + }, + "patterns": [ + { + "include": "#function-def-name" + }, + { + "include": "#parameters" + }, + { + "include": "#line-continuation" + }, + { + "include": "#return-annotation" + } + ] + }, + "function-def-name": { + "patterns": [ + { + "include": "#illegal-object-name" + }, + { + "include": "#builtin-possible-callables" + }, + { + "name": "entity.name.function.python", + "match": "(?x)\n \\b ([[:alpha:]_]\\w*) \\b\n" + } + ] + }, + "parameters": { + "name": "meta.function.parameters.python", + "begin": "(\\()", + "end": "(\\))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.parameters.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.python" + } + }, + "patterns": [ + { + "name": "keyword.operator.unpacking.parameter.python", + "match": "(\\*\\*|\\*)" + }, + { + "include": "#lambda-incomplete" + }, + { + "include": "#illegal-names" + }, + { + "include": "#illegal-object-name" + }, + { + "include": "#parameter-special" + }, + { + "match": "(?x)\n ([[:alpha:]_]\\w*)\n \\s* (?: (,) | (?=[)#\\n=]))\n", + "captures": { + "1": { + "name": "variable.parameter.function.language.python" + }, + "2": { + "name": "punctuation.separator.parameters.python" + } + } + }, + { + "include": "#comments" + }, + { + "include": "#loose-default" + }, + { + "include": "#annotated-parameter" + } + ] + }, + "parameter-special": { + "match": "(?x)\n \\b ((self)|(cls)) \\b \\s*(?:(,)|(?=\\)))\n", + "captures": { + "1": { + "name": "variable.parameter.function.language.python" + }, + "2": { + "name": "variable.parameter.function.language.special.self.python" + }, + "3": { + "name": "variable.parameter.function.language.special.cls.python" + }, + "4": { + "name": "punctuation.separator.parameters.python" + } + } + }, + "loose-default": { + "begin": "(=)", + "end": "(,)|(?=\\))", + "beginCaptures": { + "1": { + "name": "keyword.operator.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.separator.parameters.python" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "annotated-parameter": { + "begin": "(?x)\n \\b\n ([[:alpha:]_]\\w*) \\s* (:)\n", + "end": "(,)|(?=\\))", + "beginCaptures": { + "1": { + "name": "variable.parameter.function.language.python" + }, + "2": { + "name": "punctuation.separator.annotation.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.separator.parameters.python" + } + }, + "patterns": [ + { + "include": "#expression" + }, + { + "name": "keyword.operator.assignment.python", + "match": "=(?!=)" + } + ] + }, + "return-annotation": { + "begin": "(->)", + "end": "(?=:)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.annotation.result.python" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "item-access": { + "patterns": [ + { + "name": "meta.item-access.python", + "begin": "(?x)\n \\b(?=\n [[:alpha:]_]\\w* \\s* \\[\n )\n", + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.arguments.end.python" + } + }, + "patterns": [ + { + "include": "#item-name" + }, + { + "include": "#item-index" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "item-name": { + "patterns": [ + { + "include": "#special-variables" + }, + { + "include": "#builtin-functions" + }, + { + "include": "#special-names" + }, + { + "match": "(?x)\n \\b ([[:alpha:]_]\\w*) \\b\n" + } + ] + }, + "item-index": { + "begin": "(\\[)", + "end": "(?=\\])", + "beginCaptures": { + "1": { + "name": "punctuation.definition.arguments.begin.python" + } + }, + "contentName": "meta.item-access.arguments.python", + "patterns": [ + { + "name": "punctuation.separator.slice.python", + "match": ":" + }, + { + "include": "#expression" + } + ] + }, + "decorator": { + "name": "meta.function.decorator.python", + "begin": "(?x)\n ^\\s*\n (@) \\s* (?=[[:alpha:]_]\\w*)\n", + "end": + "(?x)\n ( \\) )\n # trailing whitespace and comments are legal\n (?: (.*?) (?=\\s*(?:\\#|$)) )\n | (?=\\n|\\#)\n", + "beginCaptures": { + "1": { + "name": "entity.name.function.decorator.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.arguments.end.python" + }, + "2": { + "name": "invalid.illegal.decorator.python" + } + }, + "patterns": [ + { + "include": "#decorator-name" + }, + { + "include": "#function-arguments" + } + ] + }, + "decorator-name": { + "patterns": [ + { + "include": "#builtin-callables" + }, + { + "include": "#illegal-object-name" + }, + { + "name": "entity.name.function.decorator.python", + "match": "(?x)\n ([[:alpha:]_]\\w*) | \\.\n" + }, + { + "include": "#line-continuation" + }, + { + "name": "invalid.illegal.decorator.python", + "match": "(?x)\n \\s* ([^([:alpha:]\\s_\\.#\\\\] .*?) (?=\\#|$)\n", + "captures": { + "1": { + "name": "invalid.illegal.decorator.python" + } + } + } + ] + }, + "call-wrapper-inheritance": { + "comment": "same as a function call, but in inheritance context", + "name": "meta.function-call.python", + "begin": "(?x)\n \\b(?=\n ([[:alpha:]_]\\w*) \\s* (\\()\n )\n", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.arguments.end.python" + } + }, + "patterns": [ + { + "include": "#inheritance-name" + }, + { + "include": "#function-arguments" + } + ] + }, + "inheritance-name": { + "patterns": [ + { + "include": "#lambda-incomplete" + }, + { + "include": "#builtin-possible-callables" + }, + { + "include": "#inheritance-identifier" + } + ] + }, + "function-call": { + "name": "meta.function-call.python", + "begin": "(?x)\n \\b(?=\n ([[:alpha:]_]\\w*) \\s* (\\()\n )\n", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.arguments.end.python" + } + }, + "patterns": [ + { + "include": "#special-variables" + }, + { + "include": "#function-name" + }, + { + "include": "#function-arguments" + } + ] + }, + "function-name": { + "patterns": [ + { + "include": "#builtin-possible-callables" + }, + { + "comment": "Some color schemas support meta.function-call.generic scope", + "name": "meta.function-call.generic.python", + "match": "(?x)\n \\b ([[:alpha:]_]\\w*) \\b\n" + } + ] + }, + "function-arguments": { + "begin": "(?x)\n (?:\n (\\()\n (?:\\s*(\\*\\*|\\*))?\n )\n", + "end": "(?=\\))(?!\\)\\s*\\()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.arguments.begin.python" + }, + "2": { + "name": "keyword.operator.unpacking.arguments.python" + } + }, + "contentName": "meta.function-call.arguments.python", + "patterns": [ + { + "match": "(?x)\n (?:\n (,)\n (?:\\s*(\\*\\*|\\*))?\n )\n", + "captures": { + "1": { + "name": "punctuation.separator.arguments.python" + }, + "2": { + "name": "keyword.operator.unpacking.arguments.python" + } + } + }, + { + "include": "#lambda-incomplete" + }, + { + "include": "#illegal-names" + }, + { + "match": "\\b([[:alpha:]_]\\w*)\\s*(=)(?!=)", + "captures": { + "1": { + "name": "variable.parameter.function-call.python" + }, + "2": { + "name": "keyword.operator.assignment.python" + } + } + }, + { + "name": "keyword.operator.assignment.python", + "match": "=(?!=)" + }, + { + "include": "#expression" + }, + { + "match": "\\s*(\\))\\s*(\\()", + "captures": { + "1": { + "name": "punctuation.definition.arguments.end.python" + }, + "2": { + "name": "punctuation.definition.arguments.begin.python" + } + } + } + ] + }, + "builtin-callables": { + "patterns": [ + { + "include": "#illegal-names" + }, + { + "include": "#illegal-object-name" + }, + { + "include": "#builtin-exceptions" + }, + { + "include": "#builtin-functions" + }, + { + "include": "#builtin-types" + } + ] + }, + "builtin-possible-callables": { + "patterns": [ + { + "include": "#builtin-callables" + }, + { + "include": "#magic-names" + } + ] + }, + "builtin-exceptions": { + "name": "support.type.exception.python", + "match": + "(?x) (?<!\\.) \\b(\n (\n Arithmetic | Assertion | Attribute | Buffer | BlockingIO\n | BrokenPipe | ChildProcess\n | (Connection (Aborted | Refused | Reset)?)\n | EOF | Environment | FileExists | FileNotFound\n | FloatingPoint | IO | Import | Indentation | Index | Interrupted\n | IsADirectory | NotADirectory | Permission | ProcessLookup\n | Timeout\n | Key | Lookup | Memory | Name | NotImplemented | OS | Overflow\n | Reference | Runtime | Recursion | Syntax | System\n | Tab | Type | UnboundLocal | Unicode(Encode|Decode|Translate)?\n | Value | Windows | ZeroDivision | ModuleNotFound\n ) Error\n|\n ((Pending)?Deprecation | Runtime | Syntax | User | Future | Import\n | Unicode | Bytes | Resource\n )? Warning\n|\n SystemExit | Stop(Async)?Iteration\n | KeyboardInterrupt\n | GeneratorExit | (Base)?Exception\n)\\b\n" + }, + "builtin-functions": { + "patterns": [ + { + "name": "support.function.builtin.python", + "match": + "(?x)\n (?<!\\.) \\b(\n __import__ | abs | all | any | ascii | bin | callable\n | chr | compile | copyright | credits | delattr | dir | divmod\n | enumerate | eval | exec | exit | filter | format | getattr\n | globals | hasattr | hash | help | hex | id | input\n | isinstance | issubclass | iter | len | license | locals | map\n | max | memoryview | min | next | oct | open | ord | pow | print\n | quit | range | reload | repr | reversed | round\n | setattr | sorted | sum | vars | zip\n )\\b\n" + }, + { + "name": "variable.legacy.builtin.python", + "match": + "(?x)\n (?<!\\.) \\b(\n file | reduce | intern | raw_input | unicode | cmp | basestring\n | execfile | long | xrange\n )\\b\n" + } + ] + }, + "builtin-types": { + "name": "support.type.python", + "match": + "(?x)\n (?<!\\.) \\b(\n bool | bytearray | bytes | classmethod | complex | dict\n | float | frozenset | int | list | object | property\n | set | slice | staticmethod | str | tuple | type\n\n (?# Although 'super' is not a type, it's related to types,\n and is special enough to be highlighted differently from\n other built-ins)\n | super\n )\\b\n" + }, + "magic-function-names": { + "comment": + "these methods have magic interpretation by python and are generally called\nindirectly through syntactic constructs\n", + "match": + "(?x)\n \\b(\n __(?:\n abs | add | aenter | aexit | aiter | and | anext | await\n | bool | call | ceil | cmp | coerce | complex | contains\n | copy | deepcopy | del | delattr | delete | delitem\n | delslice | dir | div | divmod | enter | eq | exit | float\n | floor | floordiv | format | ge | get | getattr\n | getattribute | getinitargs | getitem | getnewargs\n | getslice | getstate | gt | hash | hex | iadd | iand | idiv\n | ifloordiv | ilshift | imod | imul | index | init\n | instancecheck | int | invert | ior | ipow | irshift | isub\n | iter | itruediv | ixor | le | len | long | lshift | lt\n | missing | mod | mul | ne | neg | new | next | nonzero | oct | or\n | pos | pow | radd | rand | rdiv | rdivmod | reduce\n | reduce_ex | repr | reversed | rfloordiv | rlshift | rmod\n | rmul | ror | round | rpow | rrshift | rshift | rsub\n | rtruediv | rxor | set | setattr | setitem | setslice\n | setstate | sizeof | str | sub | subclasscheck | truediv\n | trunc | unicode | xor | matmul | rmatmul | imatmul\n | init_subclass | set_name | fspath | bytes | prepare\n )__\n )\\b\n", + "captures": { + "1": { + "name": "support.function.magic.python" + } + } + }, + "magic-variable-names": { + "comment": "magic variables which a class/module may have.", + "match": + "(?x)\n \\b(\n __(?:\n all | bases | builtins | class | code | debug | defaults | dict\n | doc | file | func | kwdefaults | members\n | metaclass | methods | module | mro | name\n | qualname | self | signature | slots | subclasses\n | version | weakref | wrapped | annotations | classcell\n | spec | path | package | future | traceback\n )__\n )\\b\n", + "captures": { + "1": { + "name": "support.variable.magic.python" + } + } + }, + "magic-names": { + "patterns": [ + { + "include": "#magic-function-names" + }, + { + "include": "#magic-variable-names" + } + ] + }, + "illegal-names": { + "name": "keyword.control.flow.python", + "match": + "(?x)\n \\b(\n and | as | assert | async | await | break | class | continue | def\n | del | elif | else | except | exec | finally | for | from | global\n | if | import | in | is | (?<=\\.)lambda | lambda(?=\\s*[\\.=])\n | nonlocal | not | or | pass | raise | return | try | while | with\n | yield\n )\\b\n" + }, + "special-variables": { + "match": "(?x)\n \\b (?<!\\.) (?:\n (self) | (cls)\n )\\b\n", + "captures": { + "1": { + "name": "variable.language.special.self.python" + }, + "2": { + "name": "variable.language.special.cls.python" + } + } + }, + "ellipsis": { + "name": "constant.other.ellipsis.python", + "match": "\\.\\.\\." + }, + "backticks": { + "name": "invalid.deprecated.backtick.python", + "begin": "\\`", + "end": "(?:\\`|(?<!\\\\)(\\n))", + "patterns": [ + { + "include": "#expression" + } + ] + }, + "illegal-operator": { + "patterns": [ + { + "name": "invalid.illegal.operator.python", + "match": "&&|\\|\\||--|\\+\\+" + }, + { + "name": "invalid.illegal.operator.python", + "match": "[?$]" + }, + { + "name": "invalid.illegal.operator.python", + "comment": "We don't want `!` to flash when we're typing `!=`", + "match": "!\\b" + } + ] + }, + "illegal-object-name": { + "comment": "It's illegal to name class or function \"True\"", + "name": "keyword.illegal.name.python", + "match": "\\b(True|False|None)\\b" + }, + "illegal-anno": { + "name": "invalid.illegal.annotation.python", + "match": "->" + }, + "regexp-base-expression": { + "patterns": [ + { + "include": "#regexp-quantifier" + }, + { + "include": "#regexp-base-common" + } + ] + }, + "fregexp-base-expression": { + "patterns": [ + { + "include": "#fregexp-quantifier" + }, + { + "include": "#fstring-formatting-braces" + }, + { + "match": "\\{.*?\\}" + }, + { + "include": "#regexp-base-common" + } + ] + }, + "fstring-formatting-braces": { + "patterns": [ + { + "comment": "empty braces are illegal", + "match": "({)(\\s*?)(})", + "captures": { + "1": { + "name": "constant.character.format.placeholder.other.python" + }, + "2": { + "name": "invalid.illegal.brace.python" + }, + "3": { + "name": "constant.character.format.placeholder.other.python" + } + } + }, + { + "name": "constant.character.escape.python", + "match": "({{|}})" + } + ] + }, + "regexp-base-common": { + "patterns": [ + { + "name": "support.other.match.any.regexp", + "match": "\\." + }, + { + "name": "support.other.match.begin.regexp", + "match": "\\^" + }, + { + "name": "support.other.match.end.regexp", + "match": "\\$" + }, + { + "name": "keyword.operator.quantifier.regexp", + "match": "[+*?]\\??" + }, + { + "name": "keyword.operator.disjunction.regexp", + "match": "\\|" + }, + { + "include": "#regexp-escape-sequence" + } + ] + }, + "regexp-quantifier": { + "name": "keyword.operator.quantifier.regexp", + "match": "(?x)\n \\{(\n \\d+ | \\d+,(\\d+)? | ,\\d+\n )\\}\n" + }, + "fregexp-quantifier": { + "name": "keyword.operator.quantifier.regexp", + "match": "(?x)\n \\{\\{(\n \\d+ | \\d+,(\\d+)? | ,\\d+\n )\\}\\}\n" + }, + "regexp-backreference-number": { + "name": "meta.backreference.regexp", + "match": "(\\\\[1-9]\\d?)", + "captures": { + "1": { + "name": "entity.name.tag.backreference.regexp" + } + } + }, + "regexp-backreference": { + "name": "meta.backreference.named.regexp", + "match": "(?x)\n (\\() (\\?P= \\w+(?:\\s+[[:alnum:]]+)?) (\\))\n", + "captures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.backreference.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.backreference.regexp" + }, + "3": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.backreference.named.end.regexp" + } + } + }, + "regexp-flags": { + "name": "storage.modifier.flag.regexp", + "match": "\\(\\?[aiLmsux]+\\)" + }, + "regexp-escape-special": { + "name": "support.other.escape.special.regexp", + "match": "\\\\([AbBdDsSwWZ])" + }, + "regexp-escape-character": { + "name": "constant.character.escape.regexp", + "match": + "(?x)\n \\\\ (\n x[0-9A-Fa-f]{2}\n | 0[0-7]{1,2}\n | [0-7]{3}\n )\n" + }, + "regexp-escape-unicode": { + "name": "constant.character.unicode.regexp", + "match": "(?x)\n \\\\ (\n u[0-9A-Fa-f]{4}\n | U[0-9A-Fa-f]{8}\n )\n" + }, + "regexp-escape-catchall": { + "name": "constant.character.escape.regexp", + "match": "\\\\(.|\\n)" + }, + "regexp-escape-sequence": { + "patterns": [ + { + "include": "#regexp-escape-special" + }, + { + "include": "#regexp-escape-character" + }, + { + "include": "#regexp-escape-unicode" + }, + { + "include": "#regexp-backreference-number" + }, + { + "include": "#regexp-escape-catchall" + } + ] + }, + "regexp-charecter-set-escapes": { + "patterns": [ + { + "name": "constant.character.escape.regexp", + "match": "\\\\[abfnrtv\\\\]" + }, + { + "include": "#regexp-escape-special" + }, + { + "name": "constant.character.escape.regexp", + "match": "\\\\([0-7]{1,3})" + }, + { + "include": "#regexp-escape-character" + }, + { + "include": "#regexp-escape-unicode" + }, + { + "include": "#regexp-escape-catchall" + } + ] + }, + "codetags": { + "match": "(?:\\b(NOTE|XXX|HACK|FIXME|BUG|TODO)\\b)", + "captures": { + "1": { + "name": "keyword.codetag.notation.python" + } + } + }, + "comments-base": { + "name": "comment.line.number-sign.python", + "begin": "(\\#)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.python" + } + }, + "end": "($)", + "patterns": [ + { + "include": "#codetags" + } + ] + }, + "comments-string-single-three": { + "name": "comment.line.number-sign.python", + "begin": "(\\#)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.python" + } + }, + "end": "($|(?='''))", + "patterns": [ + { + "include": "#codetags" + } + ] + }, + "comments-string-double-three": { + "name": "comment.line.number-sign.python", + "begin": "(\\#)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.python" + } + }, + "end": "($|(?=\"\"\"))", + "patterns": [ + { + "include": "#codetags" + } + ] + }, + "single-one-regexp-expression": { + "patterns": [ + { + "include": "#regexp-base-expression" + }, + { + "include": "#single-one-regexp-character-set" + }, + { + "include": "#single-one-regexp-comments" + }, + { + "include": "#regexp-flags" + }, + { + "include": "#single-one-regexp-named-group" + }, + { + "include": "#regexp-backreference" + }, + { + "include": "#single-one-regexp-lookahead" + }, + { + "include": "#single-one-regexp-lookahead-negative" + }, + { + "include": "#single-one-regexp-lookbehind" + }, + { + "include": "#single-one-regexp-lookbehind-negative" + }, + { + "include": "#single-one-regexp-conditional" + }, + { + "include": "#single-one-regexp-parentheses-non-capturing" + }, + { + "include": "#single-one-regexp-parentheses" + } + ] + }, + "single-one-regexp-character-set": { + "patterns": [ + { + "match": "(?x)\n \\[ \\^? \\] (?! .*?\\])\n" + }, + { + "name": "meta.character.set.regexp", + "begin": "(\\[)(\\^)?(\\])?", + "end": "(\\]|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "1": { + "name": + "punctuation.character.set.begin.regexp constant.other.set.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + }, + "3": { + "name": "constant.character.set.regexp" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.character.set.end.regexp constant.other.set.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#regexp-charecter-set-escapes" + }, + { + "name": "constant.character.set.regexp", + "match": "[^\\n]" + } + ] + } + ] + }, + "single-one-regexp-named-group": { + "name": "meta.named.regexp", + "begin": "(?x)\n (\\() (\\?P <\\w+(?:\\s+[[:alnum:]]+)?>)\n", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.group.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "single-one-regexp-comments": { + "name": "comment.regexp", + "begin": "\\(\\?#", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "punctuation.comment.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.comment.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#codetags" + } + ] + }, + "single-one-regexp-lookahead": { + "begin": "(\\()\\?=", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "single-one-regexp-lookahead-negative": { + "begin": "(\\()\\?!", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.negative.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "single-one-regexp-lookbehind": { + "begin": "(\\()\\?<=", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "single-one-regexp-lookbehind-negative": { + "begin": "(\\()\\?<!", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.negative.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "single-one-regexp-conditional": { + "begin": "(\\()\\?\\((\\w+(?:\\s+[[:alnum:]]+)?|\\d+)\\)", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.conditional.regexp" + }, + "1": { + "name": "punctuation.parenthesis.conditional.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.conditional.negative.regexp punctuation.parenthesis.conditional.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "single-one-regexp-parentheses-non-capturing": { + "begin": "\\(\\?:", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "single-one-regexp-parentheses": { + "begin": "\\(", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "single-three-regexp-expression": { + "patterns": [ + { + "include": "#regexp-base-expression" + }, + { + "include": "#single-three-regexp-character-set" + }, + { + "include": "#single-three-regexp-comments" + }, + { + "include": "#regexp-flags" + }, + { + "include": "#single-three-regexp-named-group" + }, + { + "include": "#regexp-backreference" + }, + { + "include": "#single-three-regexp-lookahead" + }, + { + "include": "#single-three-regexp-lookahead-negative" + }, + { + "include": "#single-three-regexp-lookbehind" + }, + { + "include": "#single-three-regexp-lookbehind-negative" + }, + { + "include": "#single-three-regexp-conditional" + }, + { + "include": "#single-three-regexp-parentheses-non-capturing" + }, + { + "include": "#single-three-regexp-parentheses" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-regexp-character-set": { + "patterns": [ + { + "match": "(?x)\n \\[ \\^? \\] (?! .*?\\])\n" + }, + { + "name": "meta.character.set.regexp", + "begin": "(\\[)(\\^)?(\\])?", + "end": "(\\]|(?=\\'\\'\\'))", + "beginCaptures": { + "1": { + "name": + "punctuation.character.set.begin.regexp constant.other.set.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + }, + "3": { + "name": "constant.character.set.regexp" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.character.set.end.regexp constant.other.set.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#regexp-charecter-set-escapes" + }, + { + "name": "constant.character.set.regexp", + "match": "[^\\n]" + } + ] + } + ] + }, + "single-three-regexp-named-group": { + "name": "meta.named.regexp", + "begin": "(?x)\n (\\() (\\?P <\\w+(?:\\s+[[:alnum:]]+)?>)\n", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.group.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-regexp-comments": { + "name": "comment.regexp", + "begin": "\\(\\?#", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "punctuation.comment.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.comment.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#codetags" + } + ] + }, + "single-three-regexp-lookahead": { + "begin": "(\\()\\?=", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-regexp-lookahead-negative": { + "begin": "(\\()\\?!", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.negative.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-regexp-lookbehind": { + "begin": "(\\()\\?<=", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-regexp-lookbehind-negative": { + "begin": "(\\()\\?<!", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.negative.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-regexp-conditional": { + "begin": "(\\()\\?\\((\\w+(?:\\s+[[:alnum:]]+)?|\\d+)\\)", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.conditional.regexp" + }, + "1": { + "name": "punctuation.parenthesis.conditional.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.conditional.negative.regexp punctuation.parenthesis.conditional.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-regexp-parentheses-non-capturing": { + "begin": "\\(\\?:", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-regexp-parentheses": { + "begin": "\\(", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "double-one-regexp-expression": { + "patterns": [ + { + "include": "#regexp-base-expression" + }, + { + "include": "#double-one-regexp-character-set" + }, + { + "include": "#double-one-regexp-comments" + }, + { + "include": "#regexp-flags" + }, + { + "include": "#double-one-regexp-named-group" + }, + { + "include": "#regexp-backreference" + }, + { + "include": "#double-one-regexp-lookahead" + }, + { + "include": "#double-one-regexp-lookahead-negative" + }, + { + "include": "#double-one-regexp-lookbehind" + }, + { + "include": "#double-one-regexp-lookbehind-negative" + }, + { + "include": "#double-one-regexp-conditional" + }, + { + "include": "#double-one-regexp-parentheses-non-capturing" + }, + { + "include": "#double-one-regexp-parentheses" + } + ] + }, + "double-one-regexp-character-set": { + "patterns": [ + { + "match": "(?x)\n \\[ \\^? \\] (?! .*?\\])\n" + }, + { + "name": "meta.character.set.regexp", + "begin": "(\\[)(\\^)?(\\])?", + "end": "(\\]|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "1": { + "name": + "punctuation.character.set.begin.regexp constant.other.set.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + }, + "3": { + "name": "constant.character.set.regexp" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.character.set.end.regexp constant.other.set.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#regexp-charecter-set-escapes" + }, + { + "name": "constant.character.set.regexp", + "match": "[^\\n]" + } + ] + } + ] + }, + "double-one-regexp-named-group": { + "name": "meta.named.regexp", + "begin": "(?x)\n (\\() (\\?P <\\w+(?:\\s+[[:alnum:]]+)?>)\n", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.group.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "double-one-regexp-comments": { + "name": "comment.regexp", + "begin": "\\(\\?#", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "punctuation.comment.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.comment.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#codetags" + } + ] + }, + "double-one-regexp-lookahead": { + "begin": "(\\()\\?=", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "double-one-regexp-lookahead-negative": { + "begin": "(\\()\\?!", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.negative.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "double-one-regexp-lookbehind": { + "begin": "(\\()\\?<=", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "double-one-regexp-lookbehind-negative": { + "begin": "(\\()\\?<!", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.negative.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "double-one-regexp-conditional": { + "begin": "(\\()\\?\\((\\w+(?:\\s+[[:alnum:]]+)?|\\d+)\\)", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.conditional.regexp" + }, + "1": { + "name": "punctuation.parenthesis.conditional.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.conditional.negative.regexp punctuation.parenthesis.conditional.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "double-one-regexp-parentheses-non-capturing": { + "begin": "\\(\\?:", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "double-one-regexp-parentheses": { + "begin": "\\(", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "double-three-regexp-expression": { + "patterns": [ + { + "include": "#regexp-base-expression" + }, + { + "include": "#double-three-regexp-character-set" + }, + { + "include": "#double-three-regexp-comments" + }, + { + "include": "#regexp-flags" + }, + { + "include": "#double-three-regexp-named-group" + }, + { + "include": "#regexp-backreference" + }, + { + "include": "#double-three-regexp-lookahead" + }, + { + "include": "#double-three-regexp-lookahead-negative" + }, + { + "include": "#double-three-regexp-lookbehind" + }, + { + "include": "#double-three-regexp-lookbehind-negative" + }, + { + "include": "#double-three-regexp-conditional" + }, + { + "include": "#double-three-regexp-parentheses-non-capturing" + }, + { + "include": "#double-three-regexp-parentheses" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-regexp-character-set": { + "patterns": [ + { + "match": "(?x)\n \\[ \\^? \\] (?! .*?\\])\n" + }, + { + "name": "meta.character.set.regexp", + "begin": "(\\[)(\\^)?(\\])?", + "end": "(\\]|(?=\"\"\"))", + "beginCaptures": { + "1": { + "name": + "punctuation.character.set.begin.regexp constant.other.set.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + }, + "3": { + "name": "constant.character.set.regexp" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.character.set.end.regexp constant.other.set.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#regexp-charecter-set-escapes" + }, + { + "name": "constant.character.set.regexp", + "match": "[^\\n]" + } + ] + } + ] + }, + "double-three-regexp-named-group": { + "name": "meta.named.regexp", + "begin": "(?x)\n (\\() (\\?P <\\w+(?:\\s+[[:alnum:]]+)?>)\n", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.group.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-regexp-comments": { + "name": "comment.regexp", + "begin": "\\(\\?#", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "punctuation.comment.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.comment.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#codetags" + } + ] + }, + "double-three-regexp-lookahead": { + "begin": "(\\()\\?=", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-regexp-lookahead-negative": { + "begin": "(\\()\\?!", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.negative.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-regexp-lookbehind": { + "begin": "(\\()\\?<=", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-regexp-lookbehind-negative": { + "begin": "(\\()\\?<!", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.negative.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-regexp-conditional": { + "begin": "(\\()\\?\\((\\w+(?:\\s+[[:alnum:]]+)?|\\d+)\\)", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.conditional.regexp" + }, + "1": { + "name": "punctuation.parenthesis.conditional.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.conditional.negative.regexp punctuation.parenthesis.conditional.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-regexp-parentheses-non-capturing": { + "begin": "\\(\\?:", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-regexp-parentheses": { + "begin": "\\(", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "regexp-single-one-line": { + "name": "string.regexp.quoted.single.python", + "begin": "\\b(([uU]r)|([bB]r)|(r[bB]?))(\\')", + "end": "(\\')|(?<!\\\\)(\\n)", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "storage.type.string.python" + }, + "5": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-regexp-expression" + } + ] + }, + "regexp-single-three-line": { + "name": "string.regexp.quoted.multi.python", + "begin": "\\b(([uU]r)|([bB]r)|(r[bB]?))(\\'\\'\\')", + "end": "(\\'\\'\\')", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "storage.type.string.python" + }, + "5": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-regexp-expression" + } + ] + }, + "regexp-double-one-line": { + "name": "string.regexp.quoted.single.python", + "begin": "\\b(([uU]r)|([bB]r)|(r[bB]?))(\")", + "end": "(\")|(?<!\\\\)(\\n)", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "storage.type.string.python" + }, + "5": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-regexp-expression" + } + ] + }, + "regexp-double-three-line": { + "name": "string.regexp.quoted.multi.python", + "begin": "\\b(([uU]r)|([bB]r)|(r[bB]?))(\"\"\")", + "end": "(\"\"\")", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "storage.type.string.python" + }, + "5": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-regexp-expression" + } + ] + }, + "single-one-fregexp-expression": { + "patterns": [ + { + "include": "#fregexp-base-expression" + }, + { + "include": "#single-one-regexp-character-set" + }, + { + "include": "#single-one-regexp-comments" + }, + { + "include": "#regexp-flags" + }, + { + "include": "#single-one-regexp-named-group" + }, + { + "include": "#regexp-backreference" + }, + { + "include": "#single-one-fregexp-lookahead" + }, + { + "include": "#single-one-fregexp-lookahead-negative" + }, + { + "include": "#single-one-fregexp-lookbehind" + }, + { + "include": "#single-one-fregexp-lookbehind-negative" + }, + { + "include": "#single-one-fregexp-conditional" + }, + { + "include": "#single-one-fregexp-parentheses-non-capturing" + }, + { + "include": "#single-one-fregexp-parentheses" + } + ] + }, + "single-one-fregexp-named-group": { + "name": "meta.named.regexp", + "begin": "(?x)\n (\\() (\\?P <\\w+(?:\\s+[[:alnum:]]+)?>)\n", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.group.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "single-one-fregexp-lookahead": { + "begin": "(\\()\\?=", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "single-one-fregexp-lookahead-negative": { + "begin": "(\\()\\?!", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.negative.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "single-one-fregexp-lookbehind": { + "begin": "(\\()\\?<=", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "single-one-fregexp-lookbehind-negative": { + "begin": "(\\()\\?<!", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.negative.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "single-one-fregexp-conditional": { + "begin": "(\\()\\?\\((\\w+(?:\\s+[[:alnum:]]+)?|\\d+)\\)", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.conditional.regexp" + }, + "1": { + "name": "punctuation.parenthesis.conditional.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.conditional.negative.regexp punctuation.parenthesis.conditional.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "single-one-fregexp-parentheses-non-capturing": { + "begin": "\\(\\?:", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "single-one-fregexp-parentheses": { + "begin": "\\(", + "end": "(\\)|(?=\\'))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "single-three-fregexp-expression": { + "patterns": [ + { + "include": "#fregexp-base-expression" + }, + { + "include": "#single-three-regexp-character-set" + }, + { + "include": "#single-three-regexp-comments" + }, + { + "include": "#regexp-flags" + }, + { + "include": "#single-three-regexp-named-group" + }, + { + "include": "#regexp-backreference" + }, + { + "include": "#single-three-fregexp-lookahead" + }, + { + "include": "#single-three-fregexp-lookahead-negative" + }, + { + "include": "#single-three-fregexp-lookbehind" + }, + { + "include": "#single-three-fregexp-lookbehind-negative" + }, + { + "include": "#single-three-fregexp-conditional" + }, + { + "include": "#single-three-fregexp-parentheses-non-capturing" + }, + { + "include": "#single-three-fregexp-parentheses" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-fregexp-named-group": { + "name": "meta.named.regexp", + "begin": "(?x)\n (\\() (\\?P <\\w+(?:\\s+[[:alnum:]]+)?>)\n", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.group.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-fregexp-lookahead": { + "begin": "(\\()\\?=", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-fregexp-lookahead-negative": { + "begin": "(\\()\\?!", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.negative.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-fregexp-lookbehind": { + "begin": "(\\()\\?<=", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-fregexp-lookbehind-negative": { + "begin": "(\\()\\?<!", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.negative.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-fregexp-conditional": { + "begin": "(\\()\\?\\((\\w+(?:\\s+[[:alnum:]]+)?|\\d+)\\)", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "keyword.operator.conditional.regexp" + }, + "1": { + "name": "punctuation.parenthesis.conditional.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.conditional.negative.regexp punctuation.parenthesis.conditional.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-fregexp-parentheses-non-capturing": { + "begin": "\\(\\?:", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "single-three-fregexp-parentheses": { + "begin": "\\(", + "end": "(\\)|(?=\\'\\'\\'))", + "beginCaptures": { + "0": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + }, + { + "include": "#comments-string-single-three" + } + ] + }, + "double-one-fregexp-expression": { + "patterns": [ + { + "include": "#fregexp-base-expression" + }, + { + "include": "#double-one-regexp-character-set" + }, + { + "include": "#double-one-regexp-comments" + }, + { + "include": "#regexp-flags" + }, + { + "include": "#double-one-regexp-named-group" + }, + { + "include": "#regexp-backreference" + }, + { + "include": "#double-one-fregexp-lookahead" + }, + { + "include": "#double-one-fregexp-lookahead-negative" + }, + { + "include": "#double-one-fregexp-lookbehind" + }, + { + "include": "#double-one-fregexp-lookbehind-negative" + }, + { + "include": "#double-one-fregexp-conditional" + }, + { + "include": "#double-one-fregexp-parentheses-non-capturing" + }, + { + "include": "#double-one-fregexp-parentheses" + } + ] + }, + "double-one-fregexp-named-group": { + "name": "meta.named.regexp", + "begin": "(?x)\n (\\() (\\?P <\\w+(?:\\s+[[:alnum:]]+)?>)\n", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.group.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "double-one-fregexp-lookahead": { + "begin": "(\\()\\?=", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "double-one-fregexp-lookahead-negative": { + "begin": "(\\()\\?!", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.negative.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "double-one-fregexp-lookbehind": { + "begin": "(\\()\\?<=", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "double-one-fregexp-lookbehind-negative": { + "begin": "(\\()\\?<!", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.negative.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "double-one-fregexp-conditional": { + "begin": "(\\()\\?\\((\\w+(?:\\s+[[:alnum:]]+)?|\\d+)\\)", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "keyword.operator.conditional.regexp" + }, + "1": { + "name": "punctuation.parenthesis.conditional.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.conditional.negative.regexp punctuation.parenthesis.conditional.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "double-one-fregexp-parentheses-non-capturing": { + "begin": "\\(\\?:", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "double-one-fregexp-parentheses": { + "begin": "\\(", + "end": "(\\)|(?=\"))|((?=(?<!\\\\)\\n))", + "beginCaptures": { + "0": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "double-three-fregexp-expression": { + "patterns": [ + { + "include": "#fregexp-base-expression" + }, + { + "include": "#double-three-regexp-character-set" + }, + { + "include": "#double-three-regexp-comments" + }, + { + "include": "#regexp-flags" + }, + { + "include": "#double-three-regexp-named-group" + }, + { + "include": "#regexp-backreference" + }, + { + "include": "#double-three-fregexp-lookahead" + }, + { + "include": "#double-three-fregexp-lookahead-negative" + }, + { + "include": "#double-three-fregexp-lookbehind" + }, + { + "include": "#double-three-fregexp-lookbehind-negative" + }, + { + "include": "#double-three-fregexp-conditional" + }, + { + "include": "#double-three-fregexp-parentheses-non-capturing" + }, + { + "include": "#double-three-fregexp-parentheses" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-fregexp-named-group": { + "name": "meta.named.regexp", + "begin": "(?x)\n (\\() (\\?P <\\w+(?:\\s+[[:alnum:]]+)?>)\n", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp" + }, + "2": { + "name": "entity.name.tag.named.group.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-fregexp-lookahead": { + "begin": "(\\()\\?=", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-fregexp-lookahead-negative": { + "begin": "(\\()\\?!", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookahead.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookahead.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookahead.negative.regexp punctuation.parenthesis.lookahead.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-fregexp-lookbehind": { + "begin": "(\\()\\?<=", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-fregexp-lookbehind-negative": { + "begin": "(\\()\\?<!", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.lookbehind.negative.regexp" + }, + "1": { + "name": "punctuation.parenthesis.lookbehind.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.lookbehind.negative.regexp punctuation.parenthesis.lookbehind.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-fregexp-conditional": { + "begin": "(\\()\\?\\((\\w+(?:\\s+[[:alnum:]]+)?|\\d+)\\)", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "keyword.operator.conditional.regexp" + }, + "1": { + "name": "punctuation.parenthesis.conditional.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "keyword.operator.conditional.negative.regexp punctuation.parenthesis.conditional.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-fregexp-parentheses-non-capturing": { + "begin": "\\(\\?:", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": + "support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "double-three-fregexp-parentheses": { + "begin": "\\(", + "end": "(\\)|(?=\"\"\"))", + "beginCaptures": { + "0": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp" + } + }, + "endCaptures": { + "1": { + "name": "support.other.parenthesis.regexp punctuation.parenthesis.end.regexp" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + }, + { + "include": "#comments-string-double-three" + } + ] + }, + "fregexp-single-one-line": { + "name": "string.interpolated.python string.regexp.quoted.single.python", + "begin": "\\b(([uU]r)|([fF]r)|(r[fF]?))(\\')", + "end": "(\\')|(?<!\\\\)(\\n)", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "storage.type.string.python" + }, + "5": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-one-fregexp-expression" + } + ] + }, + "fregexp-single-three-line": { + "name": "string.interpolated.python string.regexp.quoted.multi.python", + "begin": "\\b(([uU]r)|([fF]r)|(r[fF]?))(\\'\\'\\')", + "end": "(\\'\\'\\')", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "storage.type.string.python" + }, + "5": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#single-three-fregexp-expression" + } + ] + }, + "fregexp-double-one-line": { + "name": "string.interpolated.python string.regexp.quoted.single.python", + "begin": "\\b(([uU]r)|([fF]r)|(r[fF]?))(\")", + "end": "(\")|(?<!\\\\)(\\n)", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "storage.type.string.python" + }, + "5": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-one-fregexp-expression" + } + ] + }, + "fregexp-double-three-line": { + "name": "string.interpolated.python string.regexp.quoted.multi.python", + "begin": "\\b(([uU]r)|([fF]r)|(r[fF]?))(\"\"\")", + "end": "(\"\"\")", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "storage.type.string.python" + }, + "5": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#double-three-fregexp-expression" + } + ] + }, + "string-raw-quoted-single-line": { + "name": "string.quoted.raw.single.python", + "begin": "\\b(([uU]R)|(R))((['\"]))", + "end": "(\\4)|((?<!\\\\)\\n)", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-single-bad-brace1-formatting-raw" + }, + { + "include": "#string-single-bad-brace2-formatting-raw" + }, + { + "include": "#string-raw-guts" + } + ] + }, + "string-bin-quoted-single-line": { + "name": "string.quoted.binary.single.python", + "begin": "(\\b[bB])((['\"]))", + "end": "(\\2)|((?<!\\\\)\\n)", + "beginCaptures": { + "1": { + "name": "storage.type.string.python" + }, + "2": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-entity" + } + ] + }, + "string-raw-bin-quoted-single-line": { + "name": "string.quoted.raw.binary.single.python", + "begin": "(\\b(?:R[bB]|[bB]R))((['\"]))", + "end": "(\\2)|((?<!\\\\)\\n)", + "beginCaptures": { + "1": { + "name": "storage.type.string.python" + }, + "2": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-raw-bin-guts" + } + ] + }, + "string-quoted-single-line": { + "name": "string.quoted.single.python", + "begin": "(\\b[rR](?=[uU]))?([uU])?((['\"]))", + "end": "(\\3)|((?<!\\\\)\\n)", + "beginCaptures": { + "1": { + "name": "invalid.illegal.prefix.python" + }, + "2": { + "name": "storage.type.string.python" + }, + "3": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-single-bad-brace1-formatting-unicode" + }, + { + "include": "#string-single-bad-brace2-formatting-unicode" + }, + { + "include": "#string-unicode-guts" + } + ] + }, + "string-single-bad-brace1-formatting-unicode": { + "comment": "template using {% ... %}", + "begin": + "(?x)\n (?= \\{%\n ( .*? (?!(['\"])|((?<!\\\\)\\n)) )\n %\\}\n )\n", + "end": "(?=(['\"])|((?<!\\\\)\\n))", + "patterns": [ + { + "include": "#escape-sequence-unicode" + }, + { + "include": "#escape-sequence" + }, + { + "include": "#string-line-continuation" + } + ] + }, + "string-single-bad-brace1-formatting-raw": { + "comment": "template using {% ... %}", + "begin": + "(?x)\n (?= \\{%\n ( .*? (?!(['\"])|((?<!\\\\)\\n)) )\n %\\}\n )\n", + "end": "(?=(['\"])|((?<!\\\\)\\n))", + "patterns": [ + { + "include": "#string-consume-escape" + } + ] + }, + "string-single-bad-brace2-formatting-unicode": { + "comment": "odd format or format-like syntax", + "begin": + "(?x)\n (?!\\{\\{)\n (?= \\{ (\n \\w*? (?!(['\"])|((?<!\\\\)\\n)) [^!:\\.\\[}\\w]\n )\n .*?(?!(['\"])|((?<!\\\\)\\n))\n \\}\n )\n", + "end": "(?=(['\"])|((?<!\\\\)\\n))", + "patterns": [ + { + "include": "#escape-sequence-unicode" + }, + { + "include": "#string-entity" + } + ] + }, + "string-single-bad-brace2-formatting-raw": { + "comment": "odd format or format-like syntax", + "begin": + "(?x)\n (?!\\{\\{)\n (?= \\{ (\n \\w*? (?!(['\"])|((?<!\\\\)\\n)) [^!:\\.\\[}\\w]\n )\n .*?(?!(['\"])|((?<!\\\\)\\n))\n \\}\n )\n", + "end": "(?=(['\"])|((?<!\\\\)\\n))", + "patterns": [ + { + "include": "#string-consume-escape" + }, + { + "include": "#string-formatting" + } + ] + }, + "string-raw-quoted-multi-line": { + "name": "string.quoted.raw.multi.python", + "begin": "\\b(([uU]R)|(R))('''|\"\"\")", + "end": "(\\4)", + "beginCaptures": { + "2": { + "name": "invalid.deprecated.prefix.python" + }, + "3": { + "name": "storage.type.string.python" + }, + "4": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-multi-bad-brace1-formatting-raw" + }, + { + "include": "#string-multi-bad-brace2-formatting-raw" + }, + { + "include": "#string-raw-guts" + } + ] + }, + "string-bin-quoted-multi-line": { + "name": "string.quoted.binary.multi.python", + "begin": "(\\b[bB])('''|\"\"\")", + "end": "(\\2)", + "beginCaptures": { + "1": { + "name": "storage.type.string.python" + }, + "2": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-entity" + } + ] + }, + "string-raw-bin-quoted-multi-line": { + "name": "string.quoted.raw.binary.multi.python", + "begin": "(\\b(?:R[bB]|[bB]R))('''|\"\"\")", + "end": "(\\2)", + "beginCaptures": { + "1": { + "name": "storage.type.string.python" + }, + "2": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-raw-bin-guts" + } + ] + }, + "string-quoted-multi-line": { + "name": "string.quoted.multi.python", + "begin": "(\\b[rR](?=[uU]))?([uU])?('''|\"\"\")", + "end": "(\\3)", + "beginCaptures": { + "1": { + "name": "invalid.illegal.prefix.python" + }, + "2": { + "name": "storage.type.string.python" + }, + "3": { + "name": "punctuation.definition.string.begin.python" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#string-multi-bad-brace1-formatting-unicode" + }, + { + "include": "#string-multi-bad-brace2-formatting-unicode" + }, + { + "include": "#string-unicode-guts" + } + ] + }, + "string-multi-bad-brace1-formatting-unicode": { + "comment": "template using {% ... %}", + "begin": "(?x)\n (?= \\{%\n ( .*? (?!'''|\"\"\") )\n %\\}\n )\n", + "end": "(?='''|\"\"\")", + "patterns": [ + { + "include": "#escape-sequence-unicode" + }, + { + "include": "#escape-sequence" + }, + { + "include": "#string-line-continuation" + } + ] + }, + "string-multi-bad-brace1-formatting-raw": { + "comment": "template using {% ... %}", + "begin": "(?x)\n (?= \\{%\n ( .*? (?!'''|\"\"\") )\n %\\}\n )\n", + "end": "(?='''|\"\"\")", + "patterns": [ + { + "include": "#string-consume-escape" + } + ] + }, + "string-multi-bad-brace2-formatting-unicode": { + "comment": "odd format or format-like syntax", + "begin": + "(?x)\n (?!\\{\\{)\n (?= \\{ (\n \\w*? (?!'''|\"\"\") [^!:\\.\\[}\\w]\n )\n .*?(?!'''|\"\"\")\n \\}\n )\n", + "end": "(?='''|\"\"\")", + "patterns": [ + { + "include": "#escape-sequence-unicode" + }, + { + "include": "#string-entity" + } + ] + }, + "string-multi-bad-brace2-formatting-raw": { + "comment": "odd format or format-like syntax", + "begin": + "(?x)\n (?!\\{\\{)\n (?= \\{ (\n \\w*? (?!'''|\"\"\") [^!:\\.\\[}\\w]\n )\n .*?(?!'''|\"\"\")\n \\}\n )\n", + "end": "(?='''|\"\"\")", + "patterns": [ + { + "include": "#string-consume-escape" + }, + { + "include": "#string-formatting" + } + ] + }, + "fstring-fnorm-quoted-single-line": { + "name": "meta.fstring.python", + "begin": "(\\b[fF])([bBuU])?((['\"]))", + "end": "(\\3)|((?<!\\\\)\\n)", + "beginCaptures": { + "1": { + "name": + "string.interpolated.python string.quoted.single.python storage.type.string.python" + }, + "2": { + "name": "invalid.illegal.prefix.python" + }, + "3": { + "name": + "punctuation.definition.string.begin.python string.interpolated.python string.quoted.single.python" + } + }, + "endCaptures": { + "1": { + "name": + "punctuation.definition.string.end.python string.interpolated.python string.quoted.single.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#fstring-guts" + }, + { + "include": "#fstring-illegal-single-brace" + }, + { + "include": "#fstring-single-brace" + }, + { + "include": "#fstring-single-core" + } + ] + }, + "fstring-normf-quoted-single-line": { + "name": "meta.fstring.python", + "begin": "(\\b[bBuU])([fF])((['\"]))", + "end": "(\\3)|((?<!\\\\)\\n)", + "beginCaptures": { + "1": { + "name": "invalid.illegal.prefix.python" + }, + "2": { + "name": + "string.interpolated.python string.quoted.single.python storage.type.string.python" + }, + "3": { + "name": "punctuation.definition.string.begin.python string.quoted.single.python" + } + }, + "endCaptures": { + "1": { + "name": + "punctuation.definition.string.end.python string.interpolated.python string.quoted.single.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#fstring-guts" + }, + { + "include": "#fstring-illegal-single-brace" + }, + { + "include": "#fstring-single-brace" + }, + { + "include": "#fstring-single-core" + } + ] + }, + "fstring-raw-quoted-single-line": { + "name": "meta.fstring.python", + "begin": "(\\b(?:[R][fF]|[fF][R]))((['\"]))", + "end": "(\\2)|((?<!\\\\)\\n)", + "beginCaptures": { + "1": { + "name": + "string.interpolated.python string.quoted.raw.single.python storage.type.string.python" + }, + "2": { + "name": + "punctuation.definition.string.begin.python string.quoted.raw.single.python" + } + }, + "endCaptures": { + "1": { + "name": + "punctuation.definition.string.end.python string.interpolated.python string.quoted.raw.single.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#fstring-raw-guts" + }, + { + "include": "#fstring-illegal-single-brace" + }, + { + "include": "#fstring-single-brace" + }, + { + "include": "#fstring-raw-single-core" + } + ] + }, + "fstring-single-core": { + "name": "string.interpolated.python string.quoted.single.python", + "match": + "(?x)\n (.+?)\n (\n (?# .* and .*? in multi-line match need special handling of\n newlines otherwise SublimeText and Atom will match slightly\n differently.\n\n The guard for newlines has to be separate from the\n lookahead because of special $ matching rule.)\n ($\\n?)\n |\n (?=[\\\\\\}\\{]|(['\"])|((?<!\\\\)\\n))\n )\n (?# due to how multiline regexps are matched we need a special case\n for matching a newline character)\n | \\n\n" + }, + "fstring-raw-single-core": { + "name": "string.interpolated.python string.quoted.raw.single.python", + "match": + "(?x)\n (.+?)\n (\n (?# .* and .*? in multi-line match need special handling of\n newlines otherwise SublimeText and Atom will match slightly\n differently.\n\n The guard for newlines has to be separate from the\n lookahead because of special $ matching rule.)\n ($\\n?)\n |\n (?=[\\\\\\}\\{]|(['\"])|((?<!\\\\)\\n))\n )\n (?# due to how multiline regexps are matched we need a special case\n for matching a newline character)\n | \\n\n" + }, + "fstring-single-brace": { + "comment": "value interpolation using { ... }", + "begin": "(\\{)", + "end": "(?x)\n (\\})|(?=\\n)\n", + "beginCaptures": { + "1": { + "name": "constant.character.format.placeholder.other.python" + } + }, + "endCaptures": { + "1": { + "name": "constant.character.format.placeholder.other.python" + } + }, + "patterns": [ + { + "include": "#fstring-terminator-single" + }, + { + "include": "#f-expression" + } + ] + }, + "fstring-terminator-single": { + "patterns": [ + { + "name": "storage.type.format.python", + "match": "(![rsa])(?=})" + }, + { + "match": + "(?x)\n (![rsa])?\n ( : \\w? [<>=^]? [-+ ]? \\#?\n \\d* ,? (\\.\\d+)? [bcdeEfFgGnosxX%]? )(?=})\n", + "captures": { + "1": { + "name": "storage.type.format.python" + }, + "2": { + "name": "storage.type.format.python" + } + } + }, + { + "include": "#fstring-terminator-single-tail" + } + ] + }, + "fstring-terminator-single-tail": { + "begin": "(![rsa])?(:)(?=.*?{)", + "end": "(?=})|(?=\\n)", + "beginCaptures": { + "1": { + "name": "storage.type.format.python" + }, + "2": { + "name": "storage.type.format.python" + } + }, + "patterns": [ + { + "include": "#fstring-illegal-single-brace" + }, + { + "include": "#fstring-single-brace" + }, + { + "name": "storage.type.format.python", + "match": "([bcdeEfFgGnosxX%])(?=})" + }, + { + "name": "storage.type.format.python", + "match": "(\\.\\d+)" + }, + { + "name": "storage.type.format.python", + "match": "(,)" + }, + { + "name": "storage.type.format.python", + "match": "(\\d+)" + }, + { + "name": "storage.type.format.python", + "match": "(\\#)" + }, + { + "name": "storage.type.format.python", + "match": "([-+ ])" + }, + { + "name": "storage.type.format.python", + "match": "([<>=^])" + }, + { + "name": "storage.type.format.python", + "match": "(\\w)" + } + ] + }, + "fstring-fnorm-quoted-multi-line": { + "name": "meta.fstring.python", + "begin": "(\\b[fF])([bBuU])?('''|\"\"\")", + "end": "(\\3)", + "beginCaptures": { + "1": { + "name": + "string.interpolated.python string.quoted.multi.python storage.type.string.python" + }, + "2": { + "name": "invalid.illegal.prefix.python" + }, + "3": { + "name": + "punctuation.definition.string.begin.python string.interpolated.python string.quoted.multi.python" + } + }, + "endCaptures": { + "1": { + "name": + "punctuation.definition.string.end.python string.interpolated.python string.quoted.multi.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#fstring-guts" + }, + { + "include": "#fstring-illegal-multi-brace" + }, + { + "include": "#fstring-multi-brace" + }, + { + "include": "#fstring-multi-core" + } + ] + }, + "fstring-normf-quoted-multi-line": { + "name": "meta.fstring.python", + "begin": "(\\b[bBuU])([fF])('''|\"\"\")", + "end": "(\\3)", + "beginCaptures": { + "1": { + "name": "invalid.illegal.prefix.python" + }, + "2": { + "name": + "string.interpolated.python string.quoted.multi.python storage.type.string.python" + }, + "3": { + "name": "punctuation.definition.string.begin.python string.quoted.multi.python" + } + }, + "endCaptures": { + "1": { + "name": + "punctuation.definition.string.end.python string.interpolated.python string.quoted.multi.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#fstring-guts" + }, + { + "include": "#fstring-illegal-multi-brace" + }, + { + "include": "#fstring-multi-brace" + }, + { + "include": "#fstring-multi-core" + } + ] + }, + "fstring-raw-quoted-multi-line": { + "name": "meta.fstring.python", + "begin": "(\\b(?:[R][fF]|[fF][R]))('''|\"\"\")", + "end": "(\\2)", + "beginCaptures": { + "1": { + "name": + "string.interpolated.python string.quoted.raw.multi.python storage.type.string.python" + }, + "2": { + "name": + "punctuation.definition.string.begin.python string.quoted.raw.multi.python" + } + }, + "endCaptures": { + "1": { + "name": + "punctuation.definition.string.end.python string.interpolated.python string.quoted.raw.multi.python" + }, + "2": { + "name": "invalid.illegal.newline.python" + } + }, + "patterns": [ + { + "include": "#fstring-raw-guts" + }, + { + "include": "#fstring-illegal-multi-brace" + }, + { + "include": "#fstring-multi-brace" + }, + { + "include": "#fstring-raw-multi-core" + } + ] + }, + "fstring-multi-core": { + "name": "string.interpolated.python string.quoted.multi.python", + "match": + "(?x)\n (.+?)\n (\n (?# .* and .*? in multi-line match need special handling of\n newlines otherwise SublimeText and Atom will match slightly\n differently.\n\n The guard for newlines has to be separate from the\n lookahead because of special $ matching rule.)\n ($\\n?)\n |\n (?=[\\\\\\}\\{]|'''|\"\"\")\n )\n (?# due to how multiline regexps are matched we need a special case\n for matching a newline character)\n | \\n\n" + }, + "fstring-raw-multi-core": { + "name": "string.interpolated.python string.quoted.raw.multi.python", + "match": + "(?x)\n (.+?)\n (\n (?# .* and .*? in multi-line match need special handling of\n newlines otherwise SublimeText and Atom will match slightly\n differently.\n\n The guard for newlines has to be separate from the\n lookahead because of special $ matching rule.)\n ($\\n?)\n |\n (?=[\\\\\\}\\{]|'''|\"\"\")\n )\n (?# due to how multiline regexps are matched we need a special case\n for matching a newline character)\n | \\n\n" + }, + "fstring-multi-brace": { + "comment": "value interpolation using { ... }", + "begin": "(\\{)", + "end": "(?x)\n (\\})\n", + "beginCaptures": { + "1": { + "name": "constant.character.format.placeholder.other.python" + } + }, + "endCaptures": { + "1": { + "name": "constant.character.format.placeholder.other.python" + } + }, + "patterns": [ + { + "include": "#fstring-terminator-multi" + }, + { + "include": "#f-expression" + } + ] + }, + "fstring-terminator-multi": { + "patterns": [ + { + "name": "storage.type.format.python", + "match": "(![rsa])(?=})" + }, + { + "match": + "(?x)\n (![rsa])?\n ( : \\w? [<>=^]? [-+ ]? \\#?\n \\d* ,? (\\.\\d+)? [bcdeEfFgGnosxX%]? )(?=})\n", + "captures": { + "1": { + "name": "storage.type.format.python" + }, + "2": { + "name": "storage.type.format.python" + } + } + }, + { + "include": "#fstring-terminator-multi-tail" + } + ] + }, + "fstring-terminator-multi-tail": { + "begin": "(![rsa])?(:)(?=.*?{)", + "end": "(?=})", + "beginCaptures": { + "1": { + "name": "storage.type.format.python" + }, + "2": { + "name": "storage.type.format.python" + } + }, + "patterns": [ + { + "include": "#fstring-illegal-multi-brace" + }, + { + "include": "#fstring-multi-brace" + }, + { + "name": "storage.type.format.python", + "match": "([bcdeEfFgGnosxX%])(?=})" + }, + { + "name": "storage.type.format.python", + "match": "(\\.\\d+)" + }, + { + "name": "storage.type.format.python", + "match": "(,)" + }, + { + "name": "storage.type.format.python", + "match": "(\\d+)" + }, + { + "name": "storage.type.format.python", + "match": "(\\#)" + }, + { + "name": "storage.type.format.python", + "match": "([-+ ])" + }, + { + "name": "storage.type.format.python", + "match": "([<>=^])" + }, + { + "name": "storage.type.format.python", + "match": "(\\w)" + } + ] + } + } +} diff --git a/extensions/ruby/syntaxes/ruby.tmLanguage.json b/extensions/ruby/syntaxes/ruby.tmLanguage.json new file mode 100755 index 0000000000..7c3cab1d8a --- /dev/null +++ b/extensions/ruby/syntaxes/ruby.tmLanguage.json @@ -0,0 +1,2795 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/textmate/ruby.tmbundle/blob/master/Syntaxes/Ruby.plist", + "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/textmate/ruby.tmbundle/commit/74713556df10fbc7b1f9e99013ab1e34cd836f56", + "name": "Ruby", + "scopeName": "source.ruby", + "comment": + "\n\tTODO: unresolved issues\n\n\ttext:\n\t\"p <<end\n\tprint me!\n\tend\"\n\tsymptoms:\n\tnot recognized as a heredoc\n\tsolution:\n\tthere is no way to distinguish perfectly between the << operator and the start\n\tof a heredoc. Currently, we require assignment to recognize a heredoc. More\n\trefinement is possible.\n\t• Heredocs with indented terminators (<<-) are always distinguishable, however.\n\t• Nested heredocs are not really supportable at present\n\n\ttext:\n\tprint <<-'THERE' \n\tThis is single quoted. \n\tThe above used #{Time.now} \n\tTHERE \n\tsymtoms:\n\tFrom Programming Ruby p306; should be a non-interpolated heredoc.\n\t\n text:\n val?(a):p(b)\n val?'a':'b'\n symptoms:\n ':p' is recognized as a symbol.. its 2 things ':' and 'p'.\n :'b' has same problem.\n solution:\n ternary operator rule, precedence stuff, symbol rule.\n but also consider 'a.b?(:c)' ??\n", + "patterns": [ + { + "captures": { + "1": { + "name": "keyword.control.class.ruby" + }, + "2": { + "name": "entity.name.type.class.ruby" + }, + "3": { + "name": "keyword.operator.other.ruby" + }, + "4": { + "name": "entity.other.inherited-class.ruby" + }, + "5": { + "name": "keyword.operator.other.ruby" + }, + "6": { + "name": "variable.other.object.ruby" + } + }, + "match": + "^\\s*(class)\\s+(?:([.a-zA-Z0-9_:]+)(?:\\s*(<)\\s*([.a-zA-Z0-9_:]+))?|(<<)\\s*([.a-zA-Z0-9_:]+))", + "name": "meta.class.ruby" + }, + { + "captures": { + "1": { + "name": "keyword.control.module.ruby" + }, + "2": { + "name": "entity.name.type.module.ruby" + }, + "3": { + "name": "entity.other.inherited-class.module.first.ruby" + }, + "4": { + "name": "punctuation.separator.inheritance.ruby" + }, + "5": { + "name": "entity.other.inherited-class.module.second.ruby" + }, + "6": { + "name": "punctuation.separator.inheritance.ruby" + }, + "7": { + "name": "entity.other.inherited-class.module.third.ruby" + }, + "8": { + "name": "punctuation.separator.inheritance.ruby" + } + }, + "match": "^\\s*(module)\\s+(([A-Z]\\w*(::))?([A-Z]\\w*(::))?([A-Z]\\w*(::))*[A-Z]\\w*)", + "name": "meta.module.ruby" + }, + { + "comment": + "else if is a common mistake carried over from other languages. it works if you put in a second end, but it’s never what you want.", + "match": "(?<!\\.)\\belse(\\s)+if\\b", + "name": "invalid.deprecated.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.constant.ruby" + } + }, + "comment": "symbols as hash key (1.9 syntax)", + "match": "(?>[a-zA-Z_]\\w*(?>[?!])?)(:)(?!:)", + "name": "constant.other.symbol.hashkey.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.constant.ruby" + } + }, + "comment": "symbols as hash key (1.8 syntax)", + "match": "(?<!:)(:)(?>[a-zA-Z_]\\w*(?>[?!])?)(?=\\s*=>)", + "name": "constant.other.symbol.hashkey.ruby" + }, + { + "comment": "everything being a reserved word, not a value and needing a 'end' is a..", + "match": + "(?<!\\.)\\b(BEGIN|begin|case|class|else|elsif|END|end|ensure|for|if|in|module|rescue|then|unless|until|when|while)\\b(?![?!])", + "name": "keyword.control.ruby" + }, + { + "comment": "contextual smart pair support for block parameters", + "match": "(?<!\\.)\\bdo\\b", + "name": "keyword.control.start-block.ruby" + }, + { + "comment": "contextual smart pair support", + "match": "(?<=\\{)(\\s+)", + "name": "meta.syntax.ruby.start-block" + }, + { + "match": + "(?<!\\.)\\b(alias|alias_method|block_given[?]|break|defined[?]|iterator[?]|next|redo|retry|return|super|undef|yield)(\\b|(?<=[?]))(?![?!])", + "name": "keyword.control.pseudo-method.ruby" + }, + { + "match": "\\b(nil|true|false)\\b(?![?!])", + "name": "constant.language.ruby" + }, + { + "match": "\\b(__(FILE|LINE)__)\\b(?![?!])", + "name": "variable.language.ruby" + }, + { + "match": "\\b(self)\\b(?![?!])", + "name": "variable.language.self.ruby" + }, + { + "comment": " everything being a method but having a special function is a..", + "match": + "\\b(initialize|new|loop|include|extend|prepend|fail|raise|attr_reader|attr_writer|attr_accessor|attr|catch|throw|private|private_class_method|module_function|public|public_class_method|protected|refine|using)\\b(?![?!])", + "name": "keyword.other.special-method.ruby" + }, + { + "begin": "\\b(?<!\\.|::)(require|require_relative)\\b", + "captures": { + "1": { + "name": "keyword.other.special-method.ruby" + } + }, + "end": "$|(?=#|\\})", + "name": "meta.require.ruby", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.ruby" + } + }, + "match": "(@)[a-zA-Z_]\\w*", + "name": "variable.other.readwrite.instance.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.ruby" + } + }, + "match": "(@@)[a-zA-Z_]\\w*", + "name": "variable.other.readwrite.class.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.ruby" + } + }, + "match": "(\\$)[a-zA-Z_]\\w*", + "name": "variable.other.readwrite.global.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.ruby" + } + }, + "match": + "(\\$)(!|@|&|`|'|\\+|\\d+|~|=|/|\\\\|,|;|\\.|<|>|_|\\*|\\$|\\?|:|\"|-[0adFiIlpvw])", + "name": "variable.other.readwrite.global.pre-defined.ruby" + }, + { + "begin": "\\b(ENV)\\[", + "beginCaptures": { + "1": { + "name": "variable.other.constant.ruby" + } + }, + "end": "\\]", + "name": "meta.environment-variable.ruby", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "match": "\\b[A-Z]\\w*(?=((\\.|::)[A-Za-z]|\\[))", + "name": "support.class.ruby" + }, + { + "match": + "\\b(abort|at_exit|autoload[?]?|binding|callcc|caller|caller_locations|chomp|chop|eval|exec|exit|exit!|fork|format|gets|global_variables|gsub|lambda|load|local_variables|open|p|print|printf|proc|putc|puts|rand|readline|readlines|select|set_trace_func|sleep|spawn|sprintf|srand|sub|syscall|system|test|trace_var|trap|untrace_var|warn)(\\b|(?<=[?!]))(?![?!])", + "name": "support.function.kernel.ruby" + }, + { + "match": "\\b[_A-Z]\\w*\\b", + "name": "variable.other.constant.ruby" + }, + { + "begin": + "(?x)\n\t\t\t (?=def\\b) # an optimization to help Oniguruma fail fast\n\t\t\t (?<=^|\\s)(def)\\s+ # the def keyword\n\t\t\t ( (?>[a-zA-Z_]\\w*(?>\\.|::))? # a method name prefix\n\t\t\t (?>[a-zA-Z_]\\w*(?>[?!]|=(?!>))? # the method name\n\t\t\t |===?|!=|!~|>[>=]?|<=>|<[<=]?|[%&`/\\|^]|\\*\\*?|=?~|[-+]@?|\\[\\]=?) ) # …or an operator method\n\t\t\t \\s*(\\() # the openning parenthesis for arguments\n\t\t\t ", + "beginCaptures": { + "1": { + "name": "keyword.control.def.ruby" + }, + "2": { + "name": "entity.name.function.ruby" + }, + "3": { + "name": "punctuation.definition.parameters.ruby" + } + }, + "comment": + "the method pattern comes from the symbol pattern, see there for a explaination", + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.ruby" + } + }, + "name": "meta.function.method.with-arguments.ruby", + "patterns": [ + { + "begin": "(?=[&*_a-zA-Z])", + "end": "(?=[,)])", + "patterns": [ + { + "captures": { + "1": { + "name": "storage.type.variable.ruby" + }, + "2": { + "name": "constant.other.symbol.hashkey.parameter.function.ruby" + }, + "3": { + "name": "punctuation.definition.constant.ruby" + }, + "4": { + "name": "variable.parameter.function.ruby" + } + }, + "match": "\\G([&*]?)(?:([_a-zA-Z]\\w*(:))|([_a-zA-Z]\\w*))" + }, + { + "include": "#parens" + }, + { + "include": "#braces" + }, + { + "include": "$self" + } + ] + } + ], + "repository": { + "braces": { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.function.begin.ruby" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.section.function.end.ruby" + } + }, + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#braces" + }, + { + "include": "$self" + } + ] + }, + "parens": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.function.begin.ruby" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.function.end.ruby" + } + }, + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#braces" + }, + { + "include": "$self" + } + ] + } + } + }, + { + "begin": + "(?x)\n\t\t\t (?=def\\b) # an optimization to help Oniguruma fail fast\n\t\t\t (?<=^|\\s)(def)\\s+ # the def keyword\n\t\t\t ( (?>[a-zA-Z_]\\w*(?>\\.|::))? # a method name prefix\n\t\t\t (?>[a-zA-Z_]\\w*(?>[?!]|=(?!>))? # the method name\n\t\t\t |===?|!=|!~|>[>=]?|<=>|<[<=]?|[%&`/\\|^]|\\*\\*?|=?~|[-+]@?|\\[\\]=?) ) # …or an operator method\n\t\t\t [ \\t] # the space separating the arguments\n\t\t\t (?=[ \\t]*[^\\s#;]) # make sure arguments and not a comment follow\n\t\t\t ", + "beginCaptures": { + "1": { + "name": "keyword.control.def.ruby" + }, + "2": { + "name": "entity.name.function.ruby" + } + }, + "comment": "same as the previous rule, but without parentheses around the arguments", + "end": "$", + "name": "meta.function.method.with-arguments.ruby", + "patterns": [ + { + "begin": "(?![\\s,])", + "end": "(?=,|$)", + "patterns": [ + { + "captures": { + "1": { + "name": "storage.type.variable.ruby" + }, + "2": { + "name": "constant.other.symbol.hashkey.parameter.function.ruby" + }, + "3": { + "name": "punctuation.definition.constant.ruby" + }, + "4": { + "name": "variable.parameter.function.ruby" + } + }, + "match": "\\G([&*]?)(?:([_a-zA-Z]\\w*(:))|([_a-zA-Z]\\w*))", + "name": "variable.parameter.function.ruby" + }, + { + "include": "$self" + } + ] + } + ] + }, + { + "captures": { + "1": { + "name": "keyword.control.def.ruby" + }, + "3": { + "name": "entity.name.function.ruby" + } + }, + "comment": " the optional name is just to catch the def also without a method-name", + "match": + "(?x)\n\t\t\t (?=def\\b) # an optimization to help Oniguruma fail fast\n\t\t\t (?<=^|\\s)(def)\\b # the def keyword\n\t\t\t ( \\s+ # an optional group of whitespace followed by…\n\t\t\t ( (?>[a-zA-Z_]\\w*(?>\\.|::))? # a method name prefix\n\t\t\t (?>[a-zA-Z_]\\w*(?>[?!]|=(?!>))? # the method name\n\t\t\t |===?|!=|!~|>[>=]?|<=>|<[<=]?|[%&`/\\|^]|\\*\\*?|=?~|[-+]@?|\\[\\]=?) ) )? # …or an operator method\n\t\t\t ", + "name": "meta.function.method.without-arguments.ruby" + }, + { + "match": + "\\b\\d(?>_?\\d)*(?=\\.\\d|[eE])(\\.\\d(?>_?\\d)*)?([eE][-+]?\\d(?>_?\\d)*)?r?i?\\b", + "name": "constant.numeric.float.ruby" + }, + { + "match": "\\b(0|(0[dD]\\d|[1-9])(?>_?\\d)*)r?i?\\b", + "name": "constant.numeric.integer.ruby" + }, + { + "match": "\\b0[xX]\\h(?>_?\\h)*r?i?\\b", + "name": "constant.numeric.hex.ruby" + }, + { + "match": "\\b0[bB][01](?>_?[01])*r?i?\\b", + "name": "constant.numeric.binary.ruby" + }, + { + "match": "\\b0([oO]?[0-7](?>_?[0-7])*)?r?i?\\b", + "name": "constant.numeric.octal.ruby" + }, + { + "begin": ":'", + "captures": { + "0": { + "name": "punctuation.definition.constant.ruby" + } + }, + "end": "'", + "name": "constant.other.symbol.single-quoted.ruby", + "patterns": [ + { + "match": "\\\\['\\\\]", + "name": "constant.character.escape.ruby" + } + ] + }, + { + "begin": ":\"", + "captures": { + "0": { + "name": "punctuation.definition.constant.ruby" + } + }, + "end": "\"", + "name": "constant.other.symbol.double-quoted.ruby", + "patterns": [ + { + "include": "#interpolated_ruby" + }, + { + "include": "#escaped_char" + } + ] + }, + { + "comment": "Needs higher precidence than regular expressions.", + "match": "(?<!\\()/=", + "name": "keyword.operator.assignment.augmented.ruby" + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "comment": "single quoted string (does not allow interpolation)", + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.quoted.single.ruby", + "patterns": [ + { + "match": "\\\\'|\\\\\\\\", + "name": "constant.character.escape.ruby" + } + ] + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "comment": "double quoted string (allows for interpolation)", + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.quoted.double.ruby", + "patterns": [ + { + "include": "#interpolated_ruby" + }, + { + "include": "#escaped_char" + } + ] + }, + { + "begin": "`", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "comment": "execute string (allows for interpolation)", + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.interpolated.ruby", + "patterns": [ + { + "include": "#interpolated_ruby" + }, + { + "include": "#escaped_char" + } + ] + }, + { + "include": "#percent_literals" + }, + { + "begin": + "(?x)\n\t\t\t (?:\n\t\t\t ^ # beginning of line\n\t\t\t | (?<= # or look-behind on:\n\t\t\t [=>~(?:\\[,|&;]\n\t\t\t | [\\s;]if\\s\t\t\t# keywords\n\t\t\t | [\\s;]elsif\\s\n\t\t\t | [\\s;]while\\s\n\t\t\t | [\\s;]unless\\s\n\t\t\t | [\\s;]when\\s\n\t\t\t | [\\s;]assert_match\\s\n\t\t\t | [\\s;]or\\s\t\t\t# boolean opperators\n\t\t\t | [\\s;]and\\s\n\t\t\t | [\\s;]not\\s\n\t\t\t | [\\s.]index\\s\t\t\t# methods\n\t\t\t | [\\s.]scan\\s\n\t\t\t | [\\s.]sub\\s\n\t\t\t | [\\s.]sub!\\s\n\t\t\t | [\\s.]gsub\\s\n\t\t\t | [\\s.]gsub!\\s\n\t\t\t | [\\s.]match\\s\n\t\t\t )\n\t\t\t | (?<= # or a look-behind with line anchor:\n\t\t\t ^when\\s # duplication necessary due to limits of regex\n\t\t\t | ^if\\s\n\t\t\t | ^elsif\\s\n\t\t\t | ^while\\s\n\t\t\t | ^unless\\s\n\t\t\t )\n\t\t\t )\n\t\t\t \\s*((/))(?![*+{}?])\n\t\t\t", + "captures": { + "1": { + "name": "string.regexp.classic.ruby" + }, + "2": { + "name": "punctuation.definition.string.ruby" + } + }, + "comment": + "regular expressions (normal)\n\t\t\twe only start a regexp if the character before it (excluding whitespace)\n\t\t\tis what we think is before a regexp\n\t\t\t", + "contentName": "string.regexp.classic.ruby", + "end": "((/[eimnosux]*))", + "patterns": [ + { + "include": "#regex_sub" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.constant.ruby" + } + }, + "comment": "symbols", + "match": + "(?<!:)(:)(?>[a-zA-Z_]\\w*(?>[?!]|=(?![>=]))?|===?|>[>=]?|<=>|<[<=]?|[%&`/\\|]|\\*\\*?|=?~|[-+]@?|\\[\\]=?|(@@?|\\$)[a-zA-Z_]\\w*)", + "name": "constant.other.symbol.ruby" + }, + { + "begin": "^=begin", + "captures": { + "0": { + "name": "punctuation.definition.comment.ruby" + } + }, + "comment": "multiline comments", + "end": "^=end", + "name": "comment.block.documentation.ruby" + }, + { + "begin": "(^[ \\t]+)?(?=#)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.ruby" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "#", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.ruby" + } + }, + "end": "\\n", + "name": "comment.line.number-sign.ruby" + } + ] + }, + { + "comment": + "\n\t\t\tmatches questionmark-letters.\n\n\t\t\texamples (1st alternation = hex):\n\t\t\t?\\x1 ?\\x61\n\n\t\t\texamples (2nd alternation = octal):\n\t\t\t?\\0 ?\\07 ?\\017\n\n\t\t\texamples (3rd alternation = escaped):\n\t\t\t?\\n ?\\b\n\n\t\t\texamples (4th alternation = meta-ctrl):\n\t\t\t?\\C-a ?\\M-a ?\\C-\\M-\\C-\\M-a\n\n\t\t\texamples (4th alternation = normal):\n\t\t\t?a ?A ?0 \n\t\t\t?* ?\" ?( \n\t\t\t?. ?#\n\t\t\t\n\t\t\t\n\t\t\tthe negative lookbehind prevents against matching\n\t\t\tp(42.tainted?)\n\t\t\t", + "match": + "(?<!\\w)\\?(\\\\(x\\h{1,2}(?!\\h)\\b|0[0-7]{0,2}(?![0-7])\\b|[^x0MC])|(\\\\[MC]-)+\\w|[^\\s\\\\])", + "name": "constant.numeric.ruby" + }, + { + "begin": "^__END__\\n", + "captures": { + "0": { + "name": "string.unquoted.program-block.ruby" + } + }, + "comment": "__END__ marker", + "contentName": "text.plain", + "end": "(?=not)impossible", + "patterns": [ + { + "begin": "(?=<?xml|<(?i:html\\b)|!DOCTYPE (?i:html\\b))", + "end": "(?=not)impossible", + "name": "text.html.embedded.ruby", + "patterns": [ + { + "include": "text.html.basic" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)HTML)\\b\\1))", + "comment": "Heredoc with embedded html", + "end": "(?!\\G)", + "name": "meta.embedded.block.html", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)HTML)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "text.html", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "text.html.basic" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)XML)\\b\\1))", + "comment": "Heredoc with embedded xml", + "end": "(?!\\G)", + "name": "meta.embedded.block.xml", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)XML)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "text.xml", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "text.xml" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)SQL)\\b\\1))", + "comment": "Heredoc with embedded sql", + "end": "(?!\\G)", + "name": "meta.embedded.block.sql", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)SQL)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.sql", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.sql" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)CSS)\\b\\1))", + "comment": "Heredoc with embedded css", + "end": "(?!\\G)", + "name": "meta.embedded.block.css", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)CSS)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.css", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.css" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)CPP)\\b\\1))", + "comment": "Heredoc with embedded c++", + "end": "(?!\\G)", + "name": "meta.embedded.block.c++", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)CPP)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.c++", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.c++" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)C)\\b\\1))", + "comment": "Heredoc with embedded c", + "end": "(?!\\G)", + "name": "meta.embedded.block.c", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)C)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.c", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.c" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)(?:JS|JAVASCRIPT))\\b\\1))", + "comment": "Heredoc with embedded javascript", + "end": "(?!\\G)", + "name": "meta.embedded.block.js", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)(?:JS|JAVASCRIPT))\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.js", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.js" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)JQUERY)\\b\\1))", + "comment": "Heredoc with embedded jQuery javascript", + "end": "(?!\\G)", + "name": "meta.embedded.block.js.jquery", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)JQUERY)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.js.jquery", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.js.jquery" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)(?:SH|SHELL))\\b\\1))", + "comment": "Heredoc with embedded shell", + "end": "(?!\\G)", + "name": "meta.embedded.block.shell", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)(?:SH|SHELL))\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.shell", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.shell" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)LUA)\\b\\1))", + "comment": "Heredoc with embedded lua", + "end": "(?!\\G)", + "name": "meta.embedded.block.lua", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)LUA)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.lua", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.lua" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?=(?><<[-~](\"?)((?:[_\\w]+_|)RUBY)\\b\\1))", + "comment": "Heredoc with embedded ruby", + "end": "(?!\\G)", + "name": "meta.embedded.block.ruby", + "patterns": [ + { + "begin": "(?><<[-~](\"?)((?:[_\\w]+_|)RUBY)\\b\\1)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "contentName": "source.ruby", + "end": "\\s*\\2$\\n?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "source.ruby" + }, + { + "include": "#escaped_char" + } + ] + } + ] + }, + { + "begin": "(?>=\\s*<<(\\w+))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "end": "^\\1$", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "#escaped_char" + } + ] + }, + { + "begin": "(?><<[-~](\\w+))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "comment": "heredoc with indented terminator", + "end": "\\s*\\1$", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.unquoted.heredoc.ruby", + "patterns": [ + { + "include": "#heredoc" + }, + { + "include": "#interpolated_ruby" + }, + { + "include": "#escaped_char" + } + ] + }, + { + "begin": "(?<=\\{|do|\\{\\s|do\\s)(\\|)", + "captures": { + "1": { + "name": "punctuation.separator.arguments.ruby" + } + }, + "end": "(?<!\\|)(\\|)(?!\\|)", + "patterns": [ + { + "include": "$self" + }, + { + "match": "[_a-zA-Z][_a-zA-Z0-9]*", + "name": "variable.other.block.ruby" + }, + { + "match": ",", + "name": "punctuation.separator.variable.ruby" + } + ] + }, + { + "match": "=>", + "name": "punctuation.separator.key-value" + }, + { + "match": "->", + "name": "support.function.kernel.lambda.ruby" + }, + { + "match": "<<=|%=|&{1,2}=|\\*=|\\*\\*=|\\+=|-=|\\^=|\\|{1,2}=|<<", + "name": "keyword.operator.assignment.augmented.ruby" + }, + { + "match": "<=>|<(?!<|=)|>(?!<|=|>)|<=|>=|===|==|=~|!=|!~|(?<=[ \\t])\\?", + "name": "keyword.operator.comparison.ruby" + }, + { + "match": "(?<!\\.)\\b(and|not|or)\\b(?![?!])", + "name": "keyword.operator.logical.ruby" + }, + { + "comment": "Make sure this goes after assignment and comparison", + "match": "(?<=^|[ \\t])!|&&|\\|\\||\\^", + "name": "keyword.operator.logical.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.separator.method.ruby" + } + }, + "comment": "Safe navigation operator - Added in 2.3", + "match": "(&\\.)\\s*(?![A-Z])" + }, + { + "match": "(%|&|\\*\\*|\\*|\\+|-|/)", + "name": "keyword.operator.arithmetic.ruby" + }, + { + "match": "=", + "name": "keyword.operator.assignment.ruby" + }, + { + "match": "\\||~|>>", + "name": "keyword.operator.other.ruby" + }, + { + "match": ";", + "name": "punctuation.separator.statement.ruby" + }, + { + "match": ",", + "name": "punctuation.separator.object.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.separator.namespace.ruby" + } + }, + "comment": "Mark as namespace separator if double colons followed by capital letter", + "match": "(::)\\s*(?=[A-Z])" + }, + { + "captures": { + "1": { + "name": "punctuation.separator.method.ruby" + } + }, + "comment": "Mark as method separator if double colons not followed by capital letter", + "match": "(\\.|::)\\s*(?![A-Z])" + }, + { + "comment": "Must come after method and constant separators to prefer double colons", + "match": ":", + "name": "punctuation.separator.other.ruby" + }, + { + "match": "\\{", + "name": "punctuation.section.scope.begin.ruby" + }, + { + "match": "\\}", + "name": "punctuation.section.scope.end.ruby" + }, + { + "match": "\\[", + "name": "punctuation.section.array.begin.ruby" + }, + { + "match": "\\]", + "name": "punctuation.section.array.end.ruby" + }, + { + "match": "\\(|\\)", + "name": "punctuation.section.function.ruby" + } + ], + "repository": { + "escaped_char": { + "match": "\\\\(?:[0-7]{1,3}|x[\\da-fA-F]{1,2}|.)", + "name": "constant.character.escape.ruby" + }, + "heredoc": { + "begin": "^<<[-~]?\\w+", + "end": "$", + "patterns": [ + { + "include": "$self" + } + ] + }, + "interpolated_ruby": { + "patterns": [ + { + "begin": "#\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.ruby" + } + }, + "contentName": "source.ruby", + "end": "(\\})", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.ruby" + }, + "1": { + "name": "source.ruby" + } + }, + "name": "meta.embedded.line.ruby", + "patterns": [ + { + "include": "#nest_curly_and_self" + }, + { + "include": "$self" + } + ], + "repository": { + "nest_curly_and_self": { + "patterns": [ + { + "begin": "\\{", + "captures": { + "0": { + "name": "punctuation.section.scope.ruby" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "#nest_curly_and_self" + } + ] + }, + { + "include": "$self" + } + ] + } + } + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.ruby" + } + }, + "match": "(#@)[a-zA-Z_]\\w*", + "name": "variable.other.readwrite.instance.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.ruby" + } + }, + "match": "(#@@)[a-zA-Z_]\\w*", + "name": "variable.other.readwrite.class.ruby" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.ruby" + } + }, + "match": "(#\\$)[a-zA-Z_]\\w*", + "name": "variable.other.readwrite.global.ruby" + } + ] + }, + "percent_literals": { + "patterns": [ + { + "begin": "%i(?:([(\\[{<])|([^\\w\\s]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.section.array.begin.ruby" + } + }, + "end": "[)\\]}>]\\2|\\1\\2", + "endCaptures": { + "0": { + "name": "punctuation.section.array.end.ruby" + } + }, + "name": "meta.array.symbol.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#symbol" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#symbol" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + }, + { + "include": "#symbol" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + }, + { + "include": "#symbol" + } + ] + }, + { + "include": "#symbol" + } + ], + "repository": { + "angles": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\<|\\\\>", + "name": "constant.other.symbol.ruby" + }, + { + "begin": "<", + "captures": { + "0": { + "name": "constant.other.symbol.ruby" + } + }, + "end": ">", + "patterns": [ + { + "include": "#angles" + }, + { + "include": "#symbol" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\\\{|\\\\\\}", + "name": "constant.other.symbol.ruby" + }, + { + "begin": "\\{", + "captures": { + "0": { + "name": "constant.other.symbol.ruby" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "#braces" + }, + { + "include": "#symbol" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\\\[|\\\\\\]", + "name": "constant.other.symbol.ruby" + }, + { + "begin": "\\[", + "captures": { + "0": { + "name": "constant.other.symbol.ruby" + } + }, + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#symbol" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\\\(|\\\\\\)", + "name": "constant.other.symbol.ruby" + }, + { + "begin": "\\(", + "captures": { + "0": { + "name": "constant.other.symbol.ruby" + } + }, + "end": "\\)", + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#symbol" + } + ] + } + ] + }, + "symbol": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\\\\\|\\\\[ ]", + "name": "constant.other.symbol.ruby" + }, + { + "match": "\\S\\w*", + "name": "constant.other.symbol.ruby" + } + ] + } + } + }, + { + "begin": "%I(?:([(\\[{<])|([^\\w\\s]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.section.array.begin.ruby" + } + }, + "end": "[)\\]}>]\\2|\\1\\2", + "endCaptures": { + "0": { + "name": "punctuation.section.array.end.ruby" + } + }, + "name": "meta.array.symbol.interpolated.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#symbol" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#symbol" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + }, + { + "include": "#symbol" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + }, + { + "include": "#symbol" + } + ] + }, + { + "include": "#symbol" + } + ], + "repository": { + "angles": { + "patterns": [ + { + "begin": "<", + "captures": { + "0": { + "name": "constant.other.symbol.ruby" + } + }, + "end": ">", + "patterns": [ + { + "include": "#angles" + }, + { + "include": "#symbol" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "begin": "\\{", + "captures": { + "0": { + "name": "constant.other.symbol.ruby" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "#braces" + }, + { + "include": "#symbol" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "\\[", + "captures": { + "0": { + "name": "constant.other.symbol.ruby" + } + }, + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#symbol" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "begin": "\\(", + "captures": { + "0": { + "name": "constant.other.symbol.ruby" + } + }, + "end": "\\)", + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#symbol" + } + ] + } + ] + }, + "symbol": { + "patterns": [ + { + "begin": "(?=\\\\|#\\{)", + "end": "(?!\\G)", + "name": "constant.other.symbol.ruby", + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + } + ] + }, + { + "match": "\\S\\w*", + "name": "constant.other.symbol.ruby" + } + ] + } + } + }, + { + "begin": "%q(?:([(\\[{<])|([^\\w\\s]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "end": "[)\\]}>]\\2|\\1\\2", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.quoted.other.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + } + ] + } + ], + "repository": { + "angles": { + "patterns": [ + { + "match": "\\\\<|\\\\>|\\\\\\\\", + "name": "constant.character.escape.ruby" + }, + { + "begin": "<", + "end": ">", + "patterns": [ + { + "include": "#angles" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "match": "\\\\\\{|\\\\\\}|\\\\\\\\", + "name": "constant.character.escape.ruby" + }, + { + "begin": "\\{", + "end": "\\}", + "patterns": [ + { + "include": "#braces" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "match": "\\\\\\[|\\\\\\]|\\\\\\\\", + "name": "constant.character.escape.ruby" + }, + { + "begin": "\\[", + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "match": "\\\\\\(|\\\\\\)|\\\\\\\\", + "name": "constant.character.escape.ruby" + }, + { + "begin": "\\(", + "end": "\\)", + "patterns": [ + { + "include": "#parens" + } + ] + } + ] + } + } + }, + { + "begin": "%Q?(?:([(\\[{<])|([^\\w\\s=]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "end": "[)\\]}>]\\2|\\1\\2", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.quoted.other.interpolated.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + } + ] + }, + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + } + ], + "repository": { + "angles": { + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + }, + { + "begin": "<", + "end": ">", + "patterns": [ + { + "include": "#angles" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + }, + { + "begin": "\\{", + "end": "\\}", + "patterns": [ + { + "include": "#braces" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + }, + { + "begin": "\\[", + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + }, + { + "begin": "\\(", + "end": "\\)", + "patterns": [ + { + "include": "#parens" + } + ] + } + ] + } + } + }, + { + "begin": "%r(?:([(\\[{<])|([^\\w\\s]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "end": "([)\\]}>]\\2|\\1\\2)[eimnosux]*", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.regexp.percent.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + } + ] + }, + { + "include": "#regex_sub" + } + ], + "repository": { + "angles": { + "patterns": [ + { + "include": "#regex_sub" + }, + { + "begin": "<", + "end": ">", + "patterns": [ + { + "include": "#angles" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "include": "#regex_sub" + }, + { + "begin": "\\{", + "end": "\\}", + "patterns": [ + { + "include": "#braces" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "include": "#regex_sub" + }, + { + "begin": "\\[", + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "include": "#regex_sub" + }, + { + "begin": "\\(", + "end": "\\)", + "patterns": [ + { + "include": "#parens" + } + ] + } + ] + } + } + }, + { + "begin": "%s(?:([(\\[{<])|([^\\w\\s]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.constant.begin.ruby" + } + }, + "end": "[)\\]}>]\\2|\\1\\2", + "endCaptures": { + "0": { + "name": "punctuation.definition.constant.end.ruby" + } + }, + "name": "constant.other.symbol.percent.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + } + ] + } + ], + "repository": { + "angles": { + "patterns": [ + { + "match": "\\\\<|\\\\>|\\\\\\\\", + "name": "constant.character.escape.ruby" + }, + { + "begin": "<", + "end": ">", + "patterns": [ + { + "include": "#angles" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "match": "\\\\\\{|\\\\\\}|\\\\\\\\", + "name": "constant.character.escape.ruby" + }, + { + "begin": "\\{", + "end": "\\}", + "patterns": [ + { + "include": "#braces" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "match": "\\\\\\[|\\\\\\]|\\\\\\\\", + "name": "constant.character.escape.ruby" + }, + { + "begin": "\\[", + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "match": "\\\\\\(|\\\\\\)|\\\\\\\\", + "name": "constant.character.escape.ruby" + }, + { + "begin": "\\(", + "end": "\\)", + "patterns": [ + { + "include": "#parens" + } + ] + } + ] + } + } + }, + { + "begin": "%w(?:([(\\[{<])|([^\\w\\s]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.section.array.begin.ruby" + } + }, + "end": "[)\\]}>]\\2|\\1\\2", + "endCaptures": { + "0": { + "name": "punctuation.section.array.end.ruby" + } + }, + "name": "meta.array.string.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#string" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#string" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + }, + { + "include": "#string" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + }, + { + "include": "#string" + } + ] + }, + { + "include": "#string" + } + ], + "repository": { + "angles": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\<|\\\\>", + "name": "string.other.ruby" + }, + { + "begin": "<", + "captures": { + "0": { + "name": "string.other.ruby" + } + }, + "end": ">", + "patterns": [ + { + "include": "#angles" + }, + { + "include": "#string" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\\\{|\\\\\\}", + "name": "string.other.ruby" + }, + { + "begin": "\\{", + "captures": { + "0": { + "name": "string.other.ruby" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "#braces" + }, + { + "include": "#string" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\\\[|\\\\\\]", + "name": "string.other.ruby" + }, + { + "begin": "\\[", + "captures": { + "0": { + "name": "string.other.ruby" + } + }, + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#string" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\\\(|\\\\\\)", + "name": "string.other.ruby" + }, + { + "begin": "\\(", + "captures": { + "0": { + "name": "string.other.ruby" + } + }, + "end": "\\)", + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#string" + } + ] + } + ] + }, + "string": { + "patterns": [ + { + "captures": { + "0": { + "name": "constant.character.escape.ruby" + } + }, + "match": "\\\\\\\\|\\\\[ ]", + "name": "string.other.ruby" + }, + { + "match": "\\S\\w*", + "name": "string.other.ruby" + } + ] + } + } + }, + { + "begin": "%W(?:([(\\[{<])|([^\\w\\s]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.section.array.begin.ruby" + } + }, + "end": "[)\\]}>]\\2|\\1\\2", + "endCaptures": { + "0": { + "name": "punctuation.section.array.end.ruby" + } + }, + "name": "meta.array.string.interpolated.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#string" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#string" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + }, + { + "include": "#string" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + }, + { + "include": "#string" + } + ] + }, + { + "include": "#string" + } + ], + "repository": { + "angles": { + "patterns": [ + { + "begin": "<", + "captures": { + "0": { + "name": "string.other.ruby" + } + }, + "end": ">", + "patterns": [ + { + "include": "#angles" + }, + { + "include": "#string" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "begin": "\\{", + "captures": { + "0": { + "name": "string.other.ruby" + } + }, + "end": "\\}", + "patterns": [ + { + "include": "#braces" + }, + { + "include": "#string" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "\\[", + "captures": { + "0": { + "name": "string.other.ruby" + } + }, + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#string" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "begin": "\\(", + "captures": { + "0": { + "name": "string.other.ruby" + } + }, + "end": "\\)", + "patterns": [ + { + "include": "#parens" + }, + { + "include": "#string" + } + ] + } + ] + }, + "string": { + "patterns": [ + { + "begin": "(?=\\\\|#\\{)", + "end": "(?!\\G)", + "name": "string.other.ruby", + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + } + ] + }, + { + "match": "\\S\\w*", + "name": "string.other.ruby" + } + ] + } + } + }, + { + "begin": "%x(?:([(\\[{<])|([^\\w\\s]|_))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.ruby" + } + }, + "end": "[)\\]}>]\\2|\\1\\2", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.ruby" + } + }, + "name": "string.interpolated.percent.ruby", + "patterns": [ + { + "begin": "\\G(?<=\\()(?!\\))", + "end": "(?=\\))", + "patterns": [ + { + "include": "#parens" + } + ] + }, + { + "begin": "\\G(?<=\\[)(?!\\])", + "end": "(?=\\])", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\G(?<=\\{)(?!\\})", + "end": "(?=\\})", + "patterns": [ + { + "include": "#braces" + } + ] + }, + { + "begin": "\\G(?<=<)(?!>)", + "end": "(?=>)", + "patterns": [ + { + "include": "#angles" + } + ] + }, + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + } + ], + "repository": { + "angles": { + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + }, + { + "begin": "<", + "end": ">", + "patterns": [ + { + "include": "#angles" + } + ] + } + ] + }, + "braces": { + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + }, + { + "begin": "\\{", + "end": "\\}", + "patterns": [ + { + "include": "#braces" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + }, + { + "begin": "\\[", + "end": "\\]", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "parens": { + "patterns": [ + { + "include": "#escaped_char" + }, + { + "include": "#interpolated_ruby" + }, + { + "begin": "\\(", + "end": "\\)", + "patterns": [ + { + "include": "#parens" + } + ] + } + ] + } + } + } + ] + }, + "regex_sub": { + "patterns": [ + { + "include": "#interpolated_ruby" + }, + { + "include": "#escaped_char" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.quantifier.begin.ruby" + }, + "3": { + "name": "punctuation.definition.quantifier.end.ruby" + } + }, + "match": "(\\{)\\d+(,\\d+)?(\\})", + "name": "keyword.operator.quantifier.ruby" + }, + { + "begin": "\\[\\^?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.character-class.begin.ruby" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.character-class.end.ruby" + } + }, + "name": "constant.other.character-class.set.ruby", + "patterns": [ + { + "include": "#escaped_char" + } + ] + }, + { + "begin": "\\(\\?#", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.ruby" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.ruby" + } + }, + "name": "comment.line.number-sign.ruby", + "patterns": [ + { + "include": "#escaped_char" + } + ] + }, + { + "begin": "\\(", + "captures": { + "0": { + "name": "punctuation.definition.group.ruby" + } + }, + "end": "\\)", + "name": "meta.group.regexp.ruby", + "patterns": [ + { + "include": "#regex_sub" + } + ] + }, + { + "begin": "(?<=^|\\s)(#)\\s(?=[[a-zA-Z0-9,. \\t?!-][^\\x{00}-\\x{7F}]]*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.ruby" + } + }, + "comment": + "We are restrictive in what we allow to go after the comment character to avoid false positives, since the availability of comments depend on regexp flags.", + "end": "$\\n?", + "name": "comment.line.number-sign.ruby" + } + ] + } + } +} diff --git a/extensions/rust/syntaxes/rust.tmLanguage.json b/extensions/rust/syntaxes/rust.tmLanguage.json new file mode 100755 index 0000000000..dffdbaab5a --- /dev/null +++ b/extensions/rust/syntaxes/rust.tmLanguage.json @@ -0,0 +1,662 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/zargony/atom-language-rust/blob/master/grammars/rust.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/zargony/atom-language-rust/commit/179f449a69182cae4fcdf644d59d842b7e445f89", + "name": "Rust", + "scopeName": "source.rust", + "patterns": [ + { + "comment": "Implementation", + "begin": "\\b(impl)\\b", + "end": "\\{", + "beginCaptures": { + "1": { + "name": "storage.type.rust" + } + }, + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#sigils" + }, + { + "include": "#mut" + }, + { + "include": "#ref_lifetime" + }, + { + "include": "#core_types" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + }, + { + "include": "#where" + }, + { + "name": "storage.type.rust", + "match": "\\bfor\\b" + }, + { + "include": "#type" + } + ] + }, + { + "include": "#block_doc_comment" + }, + { + "include": "#block_comment" + }, + { + "include": "#line_doc_comment" + }, + { + "include": "#line_comment" + }, + { + "comment": "Attribute", + "name": "meta.attribute.rust", + "begin": "#\\!?\\[", + "end": "\\]", + "patterns": [ + { + "include": "#string_literal" + }, + { + "include": "#block_doc_comment" + }, + { + "include": "#block_comment" + }, + { + "include": "#line_doc_comment" + }, + { + "include": "#line_comment" + } + ] + }, + { + "comment": "Single-quote string literal (character)", + "name": "string.quoted.single.rust", + "match": + "b?'([^'\\\\]|\\\\(x[0-9A-Fa-f]{2}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.))'" + }, + { + "include": "#string_literal" + }, + { + "include": "#raw_string_literal" + }, + { + "comment": "Floating point literal (fraction)", + "name": "constant.numeric.float.rust", + "match": "\\b[0-9][0-9_]*\\.[0-9][0-9_]*([eE][+-]?[0-9_]+)?(f32|f64)?\\b" + }, + { + "comment": "Floating point literal (exponent)", + "name": "constant.numeric.float.rust", + "match": "\\b[0-9][0-9_]*(\\.[0-9][0-9_]*)?[eE][+-]?[0-9_]+(f32|f64)?\\b" + }, + { + "comment": "Floating point literal (typed)", + "name": "constant.numeric.float.rust", + "match": "\\b[0-9][0-9_]*(\\.[0-9][0-9_]*)?([eE][+-]?[0-9_]+)?(f32|f64)\\b" + }, + { + "comment": "Integer literal (decimal)", + "name": "constant.numeric.integer.decimal.rust", + "match": "\\b[0-9][0-9_]*([ui](8|16|32|64|128|s|size))?\\b" + }, + { + "comment": "Integer literal (hexadecimal)", + "name": "constant.numeric.integer.hexadecimal.rust", + "match": "\\b0x[a-fA-F0-9_]+([ui](8|16|32|64|128|s|size))?\\b" + }, + { + "comment": "Integer literal (octal)", + "name": "constant.numeric.integer.octal.rust", + "match": "\\b0o[0-7_]+([ui](8|16|32|64|128|s|size))?\\b" + }, + { + "comment": "Integer literal (binary)", + "name": "constant.numeric.integer.binary.rust", + "match": "\\b0b[01_]+([ui](8|16|32|64|128|s|size))?\\b" + }, + { + "comment": "Static storage modifier", + "name": "storage.modifier.static.rust", + "match": "\\bstatic\\b" + }, + { + "comment": "Boolean constant", + "name": "constant.language.boolean.rust", + "match": "\\b(true|false)\\b" + }, + { + "comment": "Control keyword", + "name": "keyword.control.rust", + "match": "\\b(break|continue|else|if|in|for|loop|match|return|while)\\b" + }, + { + "comment": "Keyword", + "name": "keyword.other.rust", + "match": "\\b(crate|extern|mod|let|ref|use|super|move)\\b" + }, + { + "comment": "Reserved keyword", + "name": "invalid.deprecated.rust", + "match": + "\\b(abstract|alignof|become|do|final|macro|offsetof|override|priv|proc|pure|sizeof|typeof|virtual|yield)\\b" + }, + { + "include": "#unsafe" + }, + { + "include": "#sigils" + }, + { + "include": "#self" + }, + { + "include": "#mut" + }, + { + "include": "#box" + }, + { + "include": "#lifetime" + }, + { + "include": "#ref_lifetime" + }, + { + "include": "#const" + }, + { + "include": "#pub" + }, + { + "comment": "Miscellaneous operator", + "name": "keyword.operator.misc.rust", + "match": "(=>|::|\\bas\\b)" + }, + { + "comment": "Comparison operator", + "name": "keyword.operator.comparison.rust", + "match": "(&&|\\|\\||==|!=)" + }, + { + "comment": "Assignment operator", + "name": "keyword.operator.assignment.rust", + "match": "(\\+=|-=|/=|\\*=|%=|\\^=|&=|\\|=|<<=|>>=|=)" + }, + { + "comment": "Arithmetic operator", + "name": "keyword.operator.arithmetic.rust", + "match": "(!|\\+|-|/|\\*|%|\\^|&|\\||<<|>>)" + }, + { + "comment": "Comparison operator (second group because of regex precedence)", + "name": "keyword.operator.comparison.rust", + "match": "(<=|>=|<|>)" + }, + { + "include": "#core_types" + }, + { + "include": "#core_vars" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "comment": "Built-in macro", + "name": "support.function.builtin.rust", + "match": + "\\b(macro_rules|compile_error|format_args|env|option_env|concat_idents|concat|line|column|file|stringify|include|include_str|include_bytes|module_path|cfg)!" + }, + { + "comment": "Core macro", + "name": "support.function.core.rust", + "match": + "\\b(panic|assert|assert_eq|assert_ne|debug_assert|debug_assert_eq|debug_assert_ne|try|write|writeln|unreachable|unimplemented)!" + }, + { + "comment": "Standard library macro", + "name": "support.function.std.rust", + "match": "\\b(format|print|println|eprint|eprintln|select|vec)!" + }, + { + "comment": "Logging macro", + "name": "support.function.log.rust", + "match": "\\b(log|error|warn|info|debug|trace|log_enabled)!" + }, + { + "comment": "Invokation of a macro", + "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*\\!)\\s*[({\\[]", + "captures": { + "1": { + "name": "entity.name.function.macro.rust" + } + } + }, + { + "comment": "Function call", + "match": "\\b([A-Za-z][A-Za-z0-9_]*|_[A-Za-z0-9_]+)\\s*\\(", + "captures": { + "1": { + "name": "entity.name.function.rust" + } + } + }, + { + "comment": "Function call with type parameters", + "begin": "\\b([A-Za-z][A-Za-z0-9_]*|_[A-Za-z0-9_]+)\\s*(::)(?=\\s*<.*>\\s*\\()", + "end": "\\(", + "captures": { + "1": { + "name": "entity.name.function.rust" + }, + "2": { + "name": "keyword.operator.misc.rust" + } + }, + "patterns": [ + { + "include": "#type_params" + } + ] + }, + { + "comment": "Function definition", + "begin": "\\b(fn)\\s+([A-Za-z][A-Za-z0-9_]*|_[A-Za-z0-9_]+)", + "end": "[\\{;]", + "beginCaptures": { + "1": { + "name": "keyword.other.fn.rust" + }, + "2": { + "name": "entity.name.function.rust" + } + }, + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#sigils" + }, + { + "include": "#self" + }, + { + "include": "#mut" + }, + { + "include": "#ref_lifetime" + }, + { + "include": "#core_types" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + }, + { + "include": "#const" + }, + { + "include": "#where" + }, + { + "include": "#unsafe" + }, + { + "comment": "Function arguments", + "match": "\bfn\b", + "name": "keyword.other.fn.rust" + } + ] + }, + { + "comment": "Type declaration", + "begin": "\\b(enum|struct|trait|union)\\s+([a-zA-Z_][a-zA-Z0-9_]*)", + "end": "[\\{\\(;]", + "beginCaptures": { + "1": { + "name": "storage.type.rust" + }, + "2": { + "name": "entity.name.type.rust" + } + }, + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + }, + { + "include": "#core_types" + }, + { + "include": "#pub" + }, + { + "include": "#where" + } + ] + }, + { + "comment": "Type alias", + "begin": "\\b(type)\\s+([a-zA-Z_][a-zA-Z0-9_]*)", + "end": ";", + "beginCaptures": { + "1": { + "name": "storage.type.rust" + }, + "2": { + "name": "entity.name.type.rust" + } + }, + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#sigils" + }, + { + "include": "#mut" + }, + { + "include": "#lifetime" + }, + { + "include": "#ref_lifetime" + }, + { + "include": "#core_types" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + } + ] + } + ], + "repository": { + "block_doc_comment": { + "comment": "Block documentation comment", + "name": "comment.block.documentation.rust", + "begin": "/\\*[\\*!](?![\\*/])", + "end": "\\*/", + "patterns": [ + { + "include": "#block_doc_comment" + }, + { + "include": "#block_comment" + } + ] + }, + "block_comment": { + "comment": "Block comment", + "name": "comment.block.rust", + "begin": "/\\*", + "end": "\\*/", + "patterns": [ + { + "include": "#block_doc_comment" + }, + { + "include": "#block_comment" + } + ] + }, + "line_doc_comment": { + "comment": "Single-line documentation comment", + "name": "comment.line.documentation.rust", + "begin": "//[!/](?=[^/])", + "end": "$" + }, + "line_comment": { + "comment": "Single-line comment", + "name": "comment.line.double-slash.rust", + "begin": "//", + "end": "$" + }, + "escaped_character": { + "name": "constant.character.escape.rust", + "match": "\\\\(x[0-9A-Fa-f]{2}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)" + }, + "string_literal": { + "comment": "Double-quote string literal", + "name": "string.quoted.double.rust", + "begin": "b?\"", + "end": "\"", + "patterns": [ + { + "include": "#escaped_character" + } + ] + }, + "raw_string_literal": { + "comment": "Raw double-quote string literal", + "name": "string.quoted.double.raw.rust", + "begin": "b?r(#*)\"", + "end": "\"\\1" + }, + "sigils": { + "comment": "Sigil", + "name": "keyword.operator.sigil.rust", + "match": "[&*](?=[a-zA-Z0-9_\\(\\[\\|\\\"]+)" + }, + "self": { + "comment": "Self variable", + "name": "variable.language.rust", + "match": "\\bself\\b" + }, + "mut": { + "comment": "Mutable storage modifier", + "name": "storage.modifier.mut.rust", + "match": "\\bmut\\b" + }, + "box": { + "comment": "Box storage modifier", + "name": "storage.modifier.box.rust", + "match": "\\bbox\\b" + }, + "const": { + "comment": "Const storage modifier", + "name": "storage.modifier.const.rust", + "match": "\\bconst\\b" + }, + "pub": { + "comment": "Visibility modifier", + "name": "storage.modifier.visibility.rust", + "match": "\\bpub\\b" + }, + "unsafe": { + "comment": "Unsafe code keyword", + "name": "keyword.other.unsafe.rust", + "match": "\\bunsafe\\b" + }, + "where": { + "comment": "Generic where clause", + "name": "keyword.other.where.rust", + "match": "\\bwhere\\b" + }, + "lifetime": { + "comment": "Named lifetime", + "name": "storage.modifier.lifetime.rust", + "match": "'([a-zA-Z_][a-zA-Z0-9_]*)\\b", + "captures": { + "1": { + "name": "entity.name.lifetime.rust" + } + } + }, + "ref_lifetime": { + "comment": "Reference with named lifetime", + "match": "&('([a-zA-Z_][a-zA-Z0-9_]*))\\b", + "captures": { + "1": { + "name": "storage.modifier.lifetime.rust" + }, + "2": { + "name": "entity.name.lifetime.rust" + } + } + }, + "core_types": { + "comment": "Built-in/core type", + "name": "storage.type.core.rust", + "match": + "\\b(bool|char|usize|isize|u8|u16|u32|u64|u128|i8|i16|i32|i64|i128|f32|f64|str|Self|Option|Result)\\b" + }, + "core_vars": { + "comment": "Core type variant", + "name": "support.constant.core.rust", + "match": "\\b(Some|None|Ok|Err)\\b" + }, + "core_marker": { + "comment": "Core trait (marker)", + "name": "support.type.marker.rust", + "match": "\\b(Copy|Send|Sized|Sync)\\b" + }, + "core_traits": { + "comment": "Core trait", + "name": "support.type.core.rust", + "match": + "\\b(Drop|Fn|FnMut|FnOnce|Clone|PartialEq|PartialOrd|Eq|Ord|AsRef|AsMut|Into|From|Default|Iterator|Extend|IntoIterator|DoubleEndedIterator|ExactSizeIterator)\\b" + }, + "std_types": { + "comment": "Standard library type", + "name": "storage.class.std.rust", + "match": "\\b(Box|String|Vec|Path|PathBuf)\\b" + }, + "std_traits": { + "comment": "Standard library trait", + "name": "support.type.std.rust", + "match": "\\b(ToOwned|ToString)\\b" + }, + "type": { + "comment": "A type", + "name": "entity.name.type.rust", + "match": "\\b([A-Za-z][_A-Za-z0-9]*|_[_A-Za-z0-9]+)\\b" + }, + "type_params": { + "comment": "Type parameters", + "name": "meta.type_params.rust", + "begin": "<(?![=<])", + "end": "(?<![-])>", + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#sigils" + }, + { + "include": "#mut" + }, + { + "include": "#lifetime" + }, + { + "include": "#core_types" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + } + ] + } + } +} diff --git a/extensions/shell/syntaxes/shell.tmLanguage.json b/extensions/shell/syntaxes/shell.tmLanguage.json new file mode 100755 index 0000000000..0d32b7b3b2 --- /dev/null +++ b/extensions/shell/syntaxes/shell.tmLanguage.json @@ -0,0 +1,1287 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-shellscript/blob/master/grammars/shell-unix-bash.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-shellscript/commit/4c3711edbe8eac6f501976893976b1ac6a043d50", + "name": "Shell Script", + "scopeName": "source.shell", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#pipeline" + }, + { + "include": "#list" + }, + { + "include": "#compound-command" + }, + { + "include": "#loop" + }, + { + "include": "#string" + }, + { + "include": "#function-definition" + }, + { + "include": "#variable" + }, + { + "include": "#interpolation" + }, + { + "include": "#heredoc" + }, + { + "include": "#herestring" + }, + { + "include": "#redirection" + }, + { + "include": "#pathname" + }, + { + "include": "#keyword" + }, + { + "include": "#support" + } + ], + "repository": { + "case-clause": { + "patterns": [ + { + "begin": "(?=\\S)", + "end": ";;", + "endCaptures": { + "0": { + "name": "punctuation.terminator.case-clause.shell" + } + }, + "name": "meta.scope.case-clause.shell", + "patterns": [ + { + "begin": "\\(|(?=\\S)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.case-pattern.shell" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.case-pattern.shell" + } + }, + "name": "meta.scope.case-pattern.shell", + "patterns": [ + { + "match": "\\|", + "name": "punctuation.separator.pipe-sign.shell" + }, + { + "include": "#string" + }, + { + "include": "#variable" + }, + { + "include": "#interpolation" + }, + { + "include": "#pathname" + } + ] + }, + { + "begin": "(?<=\\))", + "end": "(?=;;)", + "name": "meta.scope.case-clause-body.shell", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + } + ] + }, + "comment": { + "begin": "(^\\s+)?(?<=^|\\W)(?<!-)(?=#)(?!#{)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.shell" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "#!", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.shebang.shell" + } + }, + "end": "$", + "name": "comment.line.number-sign.shebang.shell" + }, + { + "begin": "#", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.shell" + } + }, + "end": "$", + "name": "comment.line.number-sign.shell" + } + ] + }, + "compound-command": { + "patterns": [ + { + "begin": "\\[{1,2}", + "beginCaptures": { + "0": { + "name": "punctuation.definition.logical-expression.shell" + } + }, + "end": "\\]{1,2}", + "endCaptures": { + "0": { + "name": "punctuation.definition.logical-expression.shell" + } + }, + "name": "meta.scope.logical-expression.shell", + "patterns": [ + { + "include": "#logical-expression" + }, + { + "include": "$self" + } + ] + }, + { + "begin": "\\({2}", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "\\){2}", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "string.other.math.shell", + "patterns": [ + { + "include": "#math" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.subshell.shell" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.subshell.shell" + } + }, + "name": "meta.scope.subshell.shell", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "(?<=\\s|^){(?=\\s|$)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.shell" + } + }, + "end": "(?<=^|;)\\s*(})", + "endCaptures": { + "1": { + "name": "punctuation.definition.group.shell" + } + }, + "name": "meta.scope.group.shell", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "function-definition": { + "patterns": [ + { + "begin": "(?<=^|;|&|\\s)(function)\\s+([^\\s\\\\]+)(?:\\s*(\\(\\)))?", + "beginCaptures": { + "1": { + "name": "storage.type.function.shell" + }, + "2": { + "name": "entity.name.function.shell" + }, + "3": { + "name": "punctuation.definition.arguments.shell" + } + }, + "end": ";|&|$", + "endCaptures": { + "0": { + "name": "punctuation.definition.function.shell" + } + }, + "name": "meta.function.shell", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "(?<=^|;|&|\\s)([^\\s\\\\=]+)\\s*(\\(\\))", + "beginCaptures": { + "1": { + "name": "entity.name.function.shell" + }, + "2": { + "name": "punctuation.definition.arguments.shell" + } + }, + "end": ";|&|$", + "endCaptures": { + "0": { + "name": "punctuation.definition.function.shell" + } + }, + "name": "meta.function.shell", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "heredoc": { + "patterns": [ + { + "begin": "(<<)-\\s*(\"|'|)\\s*(RUBY)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^\\t*(RUBY)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.no-indent.ruby.shell", + "contentName": "source.ruby.embedded.shell", + "patterns": [ + { + "include": "source.ruby" + } + ] + }, + { + "begin": "(<<)\\s*(\"|'|)\\s*(RUBY)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^(RUBY)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.ruby.shell", + "contentName": "source.ruby.embedded.shell", + "patterns": [ + { + "include": "source.ruby" + } + ] + }, + { + "begin": "(<<)-\\s*(\"|'|)\\s*(PYTHON)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^\\t*(PYTHON)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.no-indent.python.shell", + "contentName": "source.python.embedded.shell", + "patterns": [ + { + "include": "source.python" + } + ] + }, + { + "begin": "(<<)\\s*(\"|'|)\\s*(PYTHON)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^(PYTHON)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.python.shell", + "contentName": "source.python.embedded.shell", + "patterns": [ + { + "include": "source.python" + } + ] + }, + { + "begin": "(<<)-\\s*(\"|'|)\\s*(APPLESCRIPT)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^\\t*(APPLESCRIPT)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.no-indent.applescript.shell", + "contentName": "source.applescript.embedded.shell", + "patterns": [ + { + "include": "source.applescript" + } + ] + }, + { + "begin": "(<<)\\s*(\"|'|)\\s*(APPLESCRIPT)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^(APPLESCRIPT)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.applescript.shell", + "contentName": "source.applescript.embedded.shell", + "patterns": [ + { + "include": "source.applescript" + } + ] + }, + { + "begin": "(<<)-\\s*(\"|'|)\\s*(HTML)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^\\t*(HTML)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.no-indent.html.shell", + "contentName": "text.html.embedded.shell", + "patterns": [ + { + "include": "text.html.basic" + } + ] + }, + { + "begin": "(<<)\\s*(\"|'|)\\s*(HTML)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^(HTML)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.html.shell", + "contentName": "text.html.embedded.shell", + "patterns": [ + { + "include": "text.html.basic" + } + ] + }, + { + "begin": "(<<)-\\s*(\"|'|)\\s*(MARKDOWN)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^\\t*(MARKDOWN)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.no-indent.markdown.shell", + "contentName": "text.html.markdown.embedded.shell", + "patterns": [ + { + "include": "text.html.markdown" + } + ] + }, + { + "begin": "(<<)\\s*(\"|'|)\\s*(MARKDOWN)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^(MARKDOWN)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.markdown.shell", + "contentName": "text.html.markdown.embedded.shell", + "patterns": [ + { + "include": "text.html.markdown" + } + ] + }, + { + "begin": "(<<)-\\s*(\"|'|)\\s*(TEXTILE)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^\\t*(TEXTILE)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.no-indent.textile.shell", + "contentName": "text.html.textile.embedded.shell", + "patterns": [ + { + "include": "text.html.textile" + } + ] + }, + { + "begin": "(<<)\\s*(\"|'|)\\s*(TEXTILE)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^(TEXTILE)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.textile.shell", + "contentName": "text.html.textile.embedded.shell", + "patterns": [ + { + "include": "text.html.textile" + } + ] + }, + { + "begin": "(<<)-\\s*(\"|'|)\\s*(SHELL)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^\\t*(\\3)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "contentName": "source.shell.embedded.shell", + "name": "string.unquoted.heredoc.no-indent.shell.shell", + "patterns": [ + { + "include": "source.shell" + } + ] + }, + { + "begin": "(<<)\\s*(\"|'|)\\s*(SHELL)(?=\\s|;|&|<|\"|')\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^(\\3)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.shell.shell", + "contentName": "source.shell.embedded.shell", + "patterns": [ + { + "include": "source.shell" + } + ] + }, + { + "begin": "(<<)-\\s*(\"|'|)\\s*\\\\?([^;&<\\s]+)\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^\\t*(\\3)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.no-indent.shell" + }, + { + "begin": "(<<)\\s*(\"|'|)\\s*\\\\?([^;&<\\s]+)\\2", + "beginCaptures": { + "1": { + "name": "keyword.operator.heredoc.shell" + }, + "3": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "end": "^(\\3)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.heredoc-token.shell" + } + }, + "name": "string.unquoted.heredoc.shell" + } + ] + }, + "herestring": { + "patterns": [ + { + "begin": "(<<<)\\s*(('))", + "beginCaptures": { + "1": { + "name": "keyword.operator.herestring.shell" + }, + "2": { + "name": "string.quoted.single.shell" + }, + "3": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "(')", + "endCaptures": { + "0": { + "name": "string.quoted.single.shell" + }, + "1": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "meta.herestring.shell", + "contentName": "string.quoted.single.shell" + }, + { + "begin": "(<<<)\\s*((\"))", + "beginCaptures": { + "1": { + "name": "keyword.operator.herestring.shell" + }, + "2": { + "name": "string.quoted.double.shell" + }, + "3": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "(\")", + "endCaptures": { + "0": { + "name": "string.quoted.double.shell" + }, + "1": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "meta.herestring.shell", + "contentName": "string.quoted.double.shell" + }, + { + "captures": { + "1": { + "name": "keyword.operator.herestring.shell" + }, + "2": { + "name": "string.unquoted.herestring.shell", + "patterns": [ + { + "include": "$self" + } + ] + } + }, + "match": "(<<<)\\s*(([^\\s)\\\\]|\\\\.)+)", + "name": "meta.herestring.shell" + } + ] + }, + "interpolation": { + "patterns": [ + { + "begin": "\\$\\({2}", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "\\){2}", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "string.other.math.shell", + "patterns": [ + { + "include": "#math" + } + ] + }, + { + "begin": "`", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "string.interpolated.backtick.shell", + "patterns": [ + { + "match": "\\\\[`\\\\$]", + "name": "constant.character.escape.shell" + }, + { + "begin": "(?<=\\W)(?=#)(?!#{)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.shell" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "#", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.shell" + } + }, + "end": "(?=`)", + "name": "comment.line.number-sign.shell" + } + ] + }, + { + "include": "$self" + } + ] + }, + { + "begin": "\\$\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "string.interpolated.dollar.shell", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "keyword": { + "patterns": [ + { + "match": + "(?<=^|;|&|\\s)(then|else|elif|fi|for|in|do|done|select|case|continue|esac|while|until|return)(?=\\s|;|&|$)", + "name": "keyword.control.shell" + }, + { + "match": "(?<=^|;|&|\\s)(?:export|declare|typeset|local|readonly)(?=\\s|;|&|$)", + "name": "storage.modifier.shell" + } + ] + }, + "list": { + "patterns": [ + { + "match": ";|&&|&|\\|\\|", + "name": "keyword.operator.list.shell" + } + ] + }, + "logical-expression": { + "patterns": [ + { + "comment": "do we want a special rule for ( expr )?", + "match": "=[=~]?|!=?|<|>|&&|\\|\\|", + "name": "keyword.operator.logical.shell" + }, + { + "match": "(?<!\\S)-(nt|ot|ef|eq|ne|l[te]|g[te]|[a-hknoprstuwxzOGLSN])", + "name": "keyword.operator.logical.shell" + } + ] + }, + "loop": { + "patterns": [ + { + "begin": "(?<=^|;|&|\\s)(for)\\s+(?=\\({2})", + "beginCaptures": { + "1": { + "name": "keyword.control.shell" + } + }, + "end": "(?<=^|;|&|\\s)done(?=\\s|;|&|$)", + "endCaptures": { + "0": { + "name": "keyword.control.shell" + } + }, + "name": "meta.scope.for-loop.shell", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "(?<=^|;|&|\\s)(for)\\s+(.+?)\\s+(in)(?=\\s|;|&|$)", + "beginCaptures": { + "1": { + "name": "keyword.control.shell" + }, + "2": { + "name": "variable.other.loop.shell", + "patterns": [ + { + "include": "#string" + } + ] + }, + "3": { + "name": "keyword.control.shell" + } + }, + "end": "(?<=^|;|&|\\s)done(?=\\s|;|&|$)", + "endCaptures": { + "0": { + "name": "keyword.control.shell" + } + }, + "name": "meta.scope.for-in-loop.shell", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "(?<=^|;|&|\\s)(while|until)(?=\\s|;|&|$)", + "beginCaptures": { + "1": { + "name": "keyword.control.shell" + } + }, + "end": "(?<=^|;|&|\\s)done(?=\\s|;|&|$)", + "endCaptures": { + "0": { + "name": "keyword.control.shell" + } + }, + "name": "meta.scope.while-loop.shell", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "(?<=^|;|&|\\s)(select)\\s+((?:[^\\s\\\\]|\\\\.)+)(?=\\s|;|&|$)", + "beginCaptures": { + "1": { + "name": "keyword.control.shell" + }, + "2": { + "name": "variable.other.loop.shell" + } + }, + "end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$)", + "endCaptures": { + "1": { + "name": "keyword.control.shell" + } + }, + "name": "meta.scope.select-block.shell", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "(?<=^|;|&|\\s)case(?=\\s|;|&|$)", + "beginCaptures": { + "0": { + "name": "keyword.control.shell" + } + }, + "end": "(?<=^|;|&|\\s)esac(?=\\s|;|&|$)", + "endCaptures": { + "0": { + "name": "keyword.control.shell" + } + }, + "name": "meta.scope.case-block.shell", + "patterns": [ + { + "begin": "(?<=^|;|&|\\s)in(?=\\s|;|&|$)", + "beginCaptures": { + "0": { + "name": "keyword.control.shell" + } + }, + "end": "(?<=^|;|&|\\s)(?=esac(\\s|;|&|$))", + "name": "meta.scope.case-body.shell", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#case-clause" + }, + { + "include": "$self" + } + ] + }, + { + "include": "$self" + } + ] + }, + { + "begin": "(?<=^|;|&|\\s)if(?=\\s|;|&|$)", + "beginCaptures": { + "0": { + "name": "keyword.control.shell" + } + }, + "end": "(?<=^|;|&|\\s)fi(?=\\s|;|&|$)", + "endCaptures": { + "0": { + "name": "keyword.control.shell" + } + }, + "name": "meta.scope.if-block.shell", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "math": { + "patterns": [ + { + "include": "#variable" + }, + { + "match": + "\\+{1,2}|-{1,2}|!|~|\\*{1,2}|/|%|<[<=]?|>[>=]?|==|!=|^|\\|{1,2}|&{1,2}|\\?|\\:|,|=|[*/%+\\-&^|]=|<<=|>>=", + "name": "keyword.operator.arithmetic.shell" + }, + { + "match": "0[xX][0-9A-Fa-f]+", + "name": "constant.numeric.hex.shell" + }, + { + "match": "0\\d+", + "name": "constant.numeric.octal.shell" + }, + { + "match": "\\d{1,2}#[0-9a-zA-Z@_]+", + "name": "constant.numeric.other.shell" + }, + { + "match": "\\d+", + "name": "constant.numeric.integer.shell" + } + ] + }, + "pathname": { + "patterns": [ + { + "match": "(?<=\\s|:|=|^)~", + "name": "keyword.operator.tilde.shell" + }, + { + "match": "\\*|\\?", + "name": "keyword.operator.glob.shell" + }, + { + "begin": "([?*+@!])(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.extglob.shell" + }, + "2": { + "name": "punctuation.definition.extglob.shell" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.extglob.shell" + } + }, + "name": "meta.structure.extglob.shell", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "pipeline": { + "patterns": [ + { + "match": "(?<=^|;|&|\\s)(time)(?=\\s|;|&|$)", + "name": "keyword.other.shell" + }, + { + "match": "[|!]", + "name": "keyword.operator.pipe.shell" + } + ] + }, + "redirection": { + "patterns": [ + { + "begin": "[><]\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "string.interpolated.process-substitution.shell", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "match": "(?<![<>])(&>|\\d*>&\\d*|\\d*(>>|>|<)|\\d*<&|\\d*<>)(?![<>])", + "name": "keyword.operator.redirect.shell" + } + ] + }, + "string": { + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.shell" + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "string.quoted.single.shell" + }, + { + "begin": "\\$?\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "string.quoted.double.shell", + "patterns": [ + { + "match": "\\\\[\\$`\"\\\\\\n]", + "name": "constant.character.escape.shell" + }, + { + "include": "#variable" + }, + { + "include": "#interpolation" + } + ] + }, + { + "begin": "\\$'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.shell" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.shell" + } + }, + "name": "string.quoted.single.dollar.shell", + "patterns": [ + { + "match": "\\\\(a|b|e|f|n|r|t|v|\\\\|')", + "name": "constant.character.escape.ansi-c.shell" + }, + { + "match": "\\\\[0-9]{3}", + "name": "constant.character.escape.octal.shell" + }, + { + "match": "\\\\x[0-9a-fA-F]{2}", + "name": "constant.character.escape.hex.shell" + }, + { + "match": "\\\\c.", + "name": "constant.character.escape.control-char.shell" + } + ] + } + ] + }, + "support": { + "patterns": [ + { + "match": "(?<=^|;|&|\\s)(?::|\\.)(?=\\s|;|&|$)", + "name": "support.function.builtin.shell" + }, + { + "match": + "(?<=^|;|&|\\s)(?:alias|bg|bind|break|builtin|caller|cd|command|compgen|complete|dirs|disown|echo|enable|eval|exec|exit|false|fc|fg|getopts|hash|help|history|jobs|kill|let|logout|popd|printf|pushd|pwd|read|readonly|set|shift|shopt|source|suspend|test|times|trap|true|type|ulimit|umask|unalias|unset|wait)(?=\\s|;|&|$)", + "name": "support.function.builtin.shell" + } + ] + }, + "variable": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.variable.shell" + } + }, + "match": "(\\$)[a-zA-Z_][a-zA-Z0-9_]*", + "name": "variable.other.normal.shell" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.shell" + } + }, + "match": "(\\$)[-*@#?$!0_]", + "name": "variable.other.special.shell" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.shell" + } + }, + "match": "(\\$)[1-9]", + "name": "variable.other.positional.shell" + }, + { + "begin": "\\${", + "beginCaptures": { + "0": { + "name": "punctuation.definition.variable.shell" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.definition.variable.shell" + } + }, + "name": "variable.other.bracket.shell", + "patterns": [ + { + "match": "!|:[-=?]?|\\*|@|#{1,2}|%{1,2}|/", + "name": "keyword.operator.expansion.shell" + }, + { + "captures": { + "1": { + "name": "punctuation.section.array.shell" + }, + "3": { + "name": "punctuation.section.array.shell" + } + }, + "match": "(\\[)([^\\]]+)(\\])" + }, + { + "include": "#variable" + }, + { + "include": "#string" + } + ] + } + ] + } + } +} diff --git a/extensions/swift/syntaxes/swift.tmLanguage.json b/extensions/swift/syntaxes/swift.tmLanguage.json new file mode 100755 index 0000000000..dcf437a5cd --- /dev/null +++ b/extensions/swift/syntaxes/swift.tmLanguage.json @@ -0,0 +1,229 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/freebroccolo/atom-language-swift/blob/master/grammars/swift.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/freebroccolo/atom-language-swift/commit/fb7c93e0174dea69c8685c00deeb53d480d1d202", + "name": "Swift", + "scopeName": "source.swift", + "patterns": [ + { + "name": "keyword.others.swift", + "match": + "^\\s*(#if|#else|#endif|#elseif|@warn_unused_result|@discardableResult|@IBAction|@IBOutlet|@IBDesignable|@IBInspectable)\\b" + }, + { + "name": "keyword.declaration.swift", + "match": "\\b(deinit|import|init|subscript)\\b" + }, + { + "name": "storage.type.swift", + "match": + "\\b(precedencegroup|class|struct|enum|extension|protocol|let|var|typealias)\\b" + }, + { + "name": "storage.modifier.swift", + "match": + "\\b(final|internal|private|fileprivate|public|open|static|required|convenience)\\b" + }, + { + "name": "keyword.statement.swift", + "match": + "\\b(try|catch|repeat|break|case|continue|default|do|else|fallthrough|if|in|for|return|switch|where|while|guard|defer)\\b" + }, + { + "name": "support.type.swift", + "match": + "(?x) \\b(Character|U?Int|U?Int(8|16|32|64) |Float|Double|Float(32|64)|Bool|String|Date|Data|URL |(double|float)[234]|(double|float)[234]x[234] |Any |AnyObject |Error |Equatable |Hashable |Comparable |CustomDebugStringConvertible |CustomStringConvertible |OptionSet |ManagedBuffer |ManagedBufferPointer |BitwiseOperations |CountedSet |Counter |Directions |ExpressibleByArrayLiteral |ExpressibleByBooleanLiteral |ExpressibleByDictionaryLiteral |ExpressibleByExtendedGraphemeClusterLiteral |ExpressibleByFloatLitera |ExpressibleByIntegerLiteral |ExpressibleByNilLiteral |ExpressibleByStringInterpolation |ExpressibleByStringLiteral |ExpressibleByUnicodeScalarLiteral |OrderedSet |PaperSize |RawRepresentable |(UI|NS|CF|CG)[A-Z][a-zA-Z0-9]+ |Stream |(In|Out)putStream |FileManager |Array |Unsafe[a-zA-Z]*Pointer |Bundle |Jex)\\b" + }, + { + "name": "support.function.swift", + "match": "\\b(assert|assertionFailure|print)\\b" + }, + { + "name": "keyword.expressions-and-types.swift", + "match": + "\\b(as|dynamicType|is|new|super|self|Self|Type|#column|#file|#function|#line)\\b" + }, + { + "name": "keyword.reserved.swift", + "match": + "\\b(associativity|didSet|get|infix|inout|left|mutating|nonmutating|operator|override|postfix|precedence|prefix|right|set|unowned|unowned(safe)|unowned(unsafe)|weak|willSet)\\b" + }, + { + "name": "constant.language.swift", + "match": "\\b(true|false|nil|none)\\b" + }, + { + "name": "entity.name.function.swift", + "match": "\\bfunc\\s+([^\\t\\n\\x20\\x28]+)" + }, + { + "include": "#comment" + }, + { + "include": "#literal" + }, + { + "include": "#operator" + } + ], + "repository": { + "comment": { + "patterns": [ + { + "name": "comment.block.swift", + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.swift" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.swift" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.swift" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "name": "comment.line.double-slash.swift", + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.swift" + } + }, + "end": "\\n", + "patterns": [ + { + "name": "punctuation.separator.continuation.swift", + "match": "(?>\\\\\\s*\\n)" + } + ] + } + ] + } + ] + }, + "escaped-char": { + "patterns": [ + { + "name": "constant.character.escape.swift", + "match": "\\\\[0\\\\tnr\"']" + }, + { + "name": "constant.character.escape.swift", + "match": "\\\\(x\\h{2}|u\\h{4}|U\\h{8})" + }, + { + "name": "invalid.illegal.constant.character.escape.swift", + "match": "\\\\[^uxU]" + } + ] + }, + "identifier": { + "match": + "(?x) (?<identifier> \\g<identifier-head> \\g<identifier-characters>? | ` \\g<identifier-head> \\g<identifier-characters>? ` ){0} (?<identifier-head> [ a-z A-Z ] | [ \\u00A8 \\u00AA \\u00AD \\u00AF \\u00B2-\\u00B5 \\u00B7-\\u00BA ] | [ \\u00BC-\\u00BE \\u00C0-\\u00D6 \\u00D8-\\u00F6 \\u00F8-\\u00FF ] | [ \\u0100-\\u02FF \\u0370-\\u167F \\u1681-\\u180D \\u180F-\\u1DBF ] | [ \\u1E00-\\u1FFF ] | [ \\u200B-\\u200D \\u202A-\\u202E \\u203F-\\u2040 \\u2054 \\u2060-\\u206F ] | [ \\u2070-\\u20CF \\u2100-\\u218F \\u2460-\\u24FF \\u2776-\\u2793 ] | [ \\u2C00-\\u2DFF \\u2E80-\\u2FFF ] | [ \\u3004-\\u3007 \\u3021-\\u302F \\u3031-\\u303F \\u3040-\\uD7FF ] | [ \\uF900-\\uFD3D \\uFD40-\\uFDCF \\uFDF0-\\uFE1F \\uFE30-\\uFE44 ] | [ \\uFE47-\\uFFFD ] | [ \\u10000-\\u1FFFD \\u20000-\\u2FFFD \\u30000-\\u3FFFD \\u40000-\\u4FFFD ] | [ \\u50000-\\u5FFFD \\u60000-\\u6FFFD \\u70000-\\u7FFFD \\u80000-\\u8FFFD ] | [ \\u90000-\\u9FFFD \\uA0000-\\uAFFFD \\uB0000-\\uBFFFD \\uC0000-\\uCFFFD ] | [ \\uD0000-\\uDFFFD \\uE0000-\\uEFFFD ] ){0} (?<identifier-character> \\d | [ \\u0300-\\u036F \\u1DC0-\\u1DFF \\u20D0-\\u20FF \\uFE20-\\uFE2F ] | \\g<identifier-head> ){0} (?<identifier-characters> \\g<identifier-character> \\g<identifier-characters>? ){0} (?<implicit-parameter-name> (?<!\\g<identifier-head>) \\$ \\d+ (?!\\g<identifier-head>) (?# FIXME) ){0} \\g<identifier> | \\g<implicit-parameter-name>", + "captures": { + "5": { + "name": "variable.other.positional.swift" + } + } + }, + "literal": { + "patterns": [ + { + "include": "#literal-number" + }, + { + "include": "#literal-string" + } + ] + }, + "literal-number": { + "name": "constant.numeric.swift", + "match": + "(?x) (?### INTEGER ###) (?<integer-literal> \\g<binary-literal> | \\g<octal-literal> | \\g<hexadecimal-literal> | \\g<decimal-literal> ){0} (?### BINARY ###) (?<binary-literal> \\b 0b \\g<binary-digit> \\g<binary-literal-characters>? \\b ){0} (?<binary-digit> [0-1] ){0} (?<binary-literal-character> \\g<binary-digit> | _ ){0} (?<binary-literal-characters> \\g<binary-literal-character> \\g<binary-literal-characters>? ){0} (?### OCTAL ###) (?<octal-literal> \\b 0o \\g<octal-digit> \\g<octal-literal-characters>? \\b ){0} (?<octal-digit> [0-7] ){0} (?<octal-literal-character> \\g<octal-digit> | _ ){0} (?<octal-literal-characters> \\g<octal-literal-character> \\g<octal-literal-characters>? ){0} (?### DECIMAL ###) (?<decimal-literal> \\b \\g<decimal-digit> \\g<decimal-literal-characters>? \\b ){0} (?<decimal-digit> \\d ){0} (?<decimal-literal-character> \\g<decimal-digit> | _ ){0} (?<decimal-literal-characters> \\g<decimal-literal-character> \\g<decimal-literal-characters>? ){0} (?### HEXADECIMAL ###) (?<hexadecimal-literal> \\b 0x \\g<hexadecimal-digit> \\g<hexadecimal-literal-characters>? \\b ){0} (?<hexadecimal-digit> \\h ){0} (?<hexadecimal-literal-character> \\g<hexadecimal-digit> | _ ){0} (?<hexadecimal-literal-characters> \\g<hexadecimal-literal-character> \\g<hexadecimal-literal-characters>? ){0} (?### FLOATING POINT ###) (?<floating-point-literal> \\b \\g<decimal-literal> \\g<decimal-fraction>? \\g<decimal-exponent>? \\b | \\b \\g<hexadecimal-literal> \\g<hexadecimal-fraction>? \\g<hexadecimal-exponent> \\b ){0} (?<decimal-fraction> \\. \\g<decimal-literal> ){0} (?<decimal-exponent> \\g<floating-point-e> \\g<sign>? \\g<decimal-literal> ){0} (?<hexadecimal-fraction> \\. \\g<hexadecimal-literal>? ){0} (?<hexadecimal-exponent> \\g<floating-point-p> \\g<sign>? \\g<hexadecimal-literal> ){0} (?<floating-point-e> [eE] ){0} (?<floating-point-p> [pP] ){0} (?<sign> [+-] ){0} (?!0[box]) \\g<floating-point-literal> | \\g<integer-literal>" + }, + "literal-string": { + "name": "string.quoted.double.swift", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.swift" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.swift" + } + }, + "patterns": [ + { + "include": "#quoted-text" + } + ] + }, + "operator": { + "patterns": [ + { + "include": "#operator-character" + } + ] + }, + "operator-character": { + "name": "keyword.operator.swift", + "match": "[\\/=\\-+!*%<>&|^~,\\?:\\[\\]]" + }, + "quoted-text": { + "patterns": [ + { + "name": "meta.embedded.line.swift", + "contentName": "source.swift", + "begin": "\\\\\\(", + "end": "\\)", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.swift" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.swift" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "include": "#escaped-char" + } + ] + }, + "whitespace": { + "match": + "(?x) [ \\u0020 (?# space) \\u000A (?# line-feed) \\u000D (?# carriage-return) \\u0009 (?# horizontal-tab) \\u000B (?# vertical-tab) \\u000C (?# form-feed) \\u0000 (?# null) ]" + } + } +} From c230c69affad28d6ed3bc6309622dd5995b647ae Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Mon, 9 Apr 2018 13:51:07 -0700 Subject: [PATCH 23/59] Add @am2605 as a backer - thank you! :) --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index 031859fa81..4f0ae13cf7 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -84,6 +84,7 @@ Thanks you to all our backers for making Oni possible! ## Backers via PayPal * @mchalkley +* @am2605 ## Backers via OpenCollective From 2b86676c80a67b8290cbf77eab23d49cc49d5ead Mon Sep 17 00:00:00 2001 From: Catalin Pirvu <pirvu.catalin94@gmail.com> Date: Tue, 10 Apr 2018 00:03:50 +0300 Subject: [PATCH 24/59] Use notification api instead of alerts for recording actions (#2072) * Use notification api instead of alerts for recording actions * fix tests * Add snapshot for modified notifaction component --- .../Notifications/NotificationsView.tsx | 4 +++- browser/src/Services/Recorder.ts | 13 ++++++++++-- test/demo/HeroScreenshot.ts | 20 ++++++++++++------- .../NotificationView.test.tsx.snap | 4 +++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/browser/src/Services/Notifications/NotificationsView.tsx b/browser/src/Services/Notifications/NotificationsView.tsx index 6f1d456f5c..0405b4e6d1 100644 --- a/browser/src/Services/Notifications/NotificationsView.tsx +++ b/browser/src/Services/Notifications/NotificationsView.tsx @@ -261,7 +261,9 @@ export class NotificationView extends React.PureComponent<INotification, {}> { <NotificationTitle level={level}>{this.props.title}</NotificationTitle> </NotificationHeader> <NotificationContents> - <NotificationDescription>{this.props.detail}</NotificationDescription> + <NotificationDescription className="notification-description"> + {this.props.detail} + </NotificationDescription> </NotificationContents> {buttons && <Buttons buttons={buttons} />} </NotificationWrapper> diff --git a/browser/src/Services/Recorder.ts b/browser/src/Services/Recorder.ts index a8f8dee9b9..9632fb2078 100644 --- a/browser/src/Services/Recorder.ts +++ b/browser/src/Services/Recorder.ts @@ -15,6 +15,7 @@ import * as Oni from "oni-api" import * as Log from "./../Log" import { configuration } from "./Configuration" +import { getInstance as getNotificationsInstance } from "./Notifications" declare var MediaRecorder: any @@ -98,7 +99,11 @@ class Recorder implements Oni.Recorder { this._recorder = null this._blobs = [] - alert("Recording saved to: " + videoFilePath) + + const notification = getNotificationsInstance().createItem() + notification.setContents("Recording finished", "Recording saved to: " + videoFilePath) + notification.setLevel("success") + notification.show() } public takeScreenshot(fileName?: string, scale: number = 1): void { @@ -112,7 +117,11 @@ class Recorder implements Oni.Recorder { if (configuration.getValue("recorder.copyScreenshotToClipboard")) { clipboard.writeImage(screenshotPath as any) } - alert("Screenshot saved to: " + screenshotPath) + + const notification = getNotificationsInstance().createItem() + notification.setContents("Screenshot taken", "Screenshot saved to " + screenshotPath) + notification.setLevel("success") + notification.show() }) } diff --git a/test/demo/HeroScreenshot.ts b/test/demo/HeroScreenshot.ts index 643e2fdfab..2c6efcefcf 100644 --- a/test/demo/HeroScreenshot.ts +++ b/test/demo/HeroScreenshot.ts @@ -22,12 +22,19 @@ const getCompletionElement = () => { } } +const getNotificationText = () => { + const elements = document.body.getElementsByClassName("notification-description") + + if (!elements || !elements.length) { + return null + } else { + return elements[0].innerHTML + } +} + export const test = async (oni: any) => { await oni.automation.waitForEditors() - let lastAlertText = null - window.alert = myText => (lastAlertText = myText) - // Use the `Completion.ts` file as the screenshot source remote.getCurrentWindow().setSize(1200, 800) @@ -76,13 +83,12 @@ export const test = async (oni: any) => { 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) + await oni.automation.waitFor(() => getNotificationText() !== null, 20000) + console.log("Alert text (screenshot output path): " + getNotificationText()) } export const settings = { config: { - "notifications.enabled": false, + "notifications.enabled": true, }, } diff --git a/ui-tests/__snapshots__/NotificationView.test.tsx.snap b/ui-tests/__snapshots__/NotificationView.test.tsx.snap index 6e4feedfc6..5762f4dbb8 100644 --- a/ui-tests/__snapshots__/NotificationView.test.tsx.snap +++ b/ui-tests/__snapshots__/NotificationView.test.tsx.snap @@ -41,7 +41,9 @@ exports[`<NotificationsView /> should match the snapshot 1`] = ` </styled.div> </styled.header> <styled.div> - <styled.div> + <styled.div + className="notification-description" + > this is a test </styled.div> </styled.div> From 18f8546d88025718cf893f9f1b23fa16b067ce04 Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Tue, 10 Apr 2018 04:34:15 +0100 Subject: [PATCH 25/59] Feature: add prompt to use init vim if one is found (#1942) * add prompt to use init vim if one is found * add check to ensure no option set before prompting user * create common method to get init.vim path * add [wip] ci test for notification * Revert to using a false check * Add refactored getInitVim methods use _internal flag to check if user has been prompted to use init vim Add [WIP] ciTest * add an index to the buttons * remove console.logs from test * readd ci tests * remove redundant double set values call for notification * update notification snap shot * fix naming issue with notification title flesh out ci test * update snapshot tests * use sleep condition not classname * move initvim test to the top of Ci tests trying to determine if there is an issue if other tests run before it * create init.vim for CI pass in env object rather than calc config path and passing that alone * fix typo in init.vim msg --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 39 +++++++++- .../Services/Configuration/Configuration.ts | 4 +- .../Notifications/NotificationsView.tsx | 24 ++++-- browser/src/Utility.ts | 12 +++ browser/src/neovim/NeovimInstance.ts | 39 ++++++++-- test/CiTests.ts | 1 + test/ci/Common.ts | 3 + test/ci/initVimPromptNotificationTest.ts | 73 +++++++++++++++++++ test/common/Oni.ts | 8 +- test/common/runInProcTest.ts | 13 +++- .../NotificationView.test.tsx.snap | 2 + 11 files changed, 196 insertions(+), 22 deletions(-) create mode 100644 test/ci/initVimPromptNotificationTest.ts diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 102652ca0c..b550515e37 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -242,9 +242,9 @@ export class NeovimEditor extends Editor implements IEditor { this._toolTipsProvider, ) + const notificationManager = getNotificationsInstance() this._neovimInstance.onMessage.subscribe(messageInfo => { // TODO: Hook up real notifications - const notificationManager = getNotificationsInstance() const notification = notificationManager.createItem() notification.setLevel("error") notification.setContents(messageInfo.title, messageInfo.details) @@ -254,6 +254,43 @@ export class NeovimEditor extends Editor implements IEditor { notification.show() }) + const initVimPath = this._neovimInstance.doesInitVimExist() + const initVimInUse = this._configuration.getValue("oni.loadInitVim") + const hasCheckedInitVim = this._configuration.getValue("_internal.hasCheckedInitVim") + + if (initVimPath && !initVimInUse && !hasCheckedInitVim) { + const initVimNotification = notificationManager.createItem() + initVimNotification.setLevel("info") + initVimNotification.setContents( + "init.vim found", + `We found an init.vim file would you like Oni to use it? + This will result in Oni being reloaded`, + ) + + initVimNotification.setButtons([ + { + title: "Yes", + callback: () => { + this._configuration.setValues( + { "_internal.hasCheckedInitVim": true, "oni.loadInitVim": true }, + true, + ) + commandManager.executeCommand("oni.debug.reload") + }, + }, + { + title: "No", + callback: () => { + this._configuration.setValues( + { "oni.loadInitVim": false, "_internal.hasCheckedInitVim": true }, + true, + ) + }, + }, + ]) + initVimNotification.show() + } + this._renderer = new CanvasRenderer() this._rename = new Rename( diff --git a/browser/src/Services/Configuration/Configuration.ts b/browser/src/Services/Configuration/Configuration.ts index e64142a3c6..e6692b511c 100644 --- a/browser/src/Services/Configuration/Configuration.ts +++ b/browser/src/Services/Configuration/Configuration.ts @@ -239,8 +239,8 @@ export class Configuration implements Oni.Configuration { return !!this.getValue(configValue) } - public setValue(valueName: string, value: any): void { - return this.setValues({ [valueName]: value }) + public setValue(valueName: string, value: any, persist: boolean = false): void { + return this.setValues({ [valueName]: value }, persist) } public setValues(configValues: { [configValue: string]: any }, persist: boolean = false): void { diff --git a/browser/src/Services/Notifications/NotificationsView.tsx b/browser/src/Services/Notifications/NotificationsView.tsx index 0405b4e6d1..f993eeaac7 100644 --- a/browser/src/Services/Notifications/NotificationsView.tsx +++ b/browser/src/Services/Notifications/NotificationsView.tsx @@ -214,14 +214,21 @@ export const Button = styled.button` interface IButtonProps { buttons: INotificationButton[] + onClose: () => void } -const Buttons = ({ buttons }: IButtonProps) => { +const Buttons = ({ buttons, onClose }: IButtonProps) => { + const executeThenClose = (callback: (args?: any) => void) => () => { + callback() + onClose() + } return ( - <ButtonRow> - {buttons.map(({ callback, title }) => ( - <Sneakable callback={callback}> - <Button onClick={callback}>{title}</Button> + <ButtonRow data-test="notification-buttons"> + {buttons.map(({ callback, title }, index) => ( + <Sneakable key={`${title}-${index}`} callback={executeThenClose(callback)}> + <Button data-test={`notification-${title.toLowerCase()}`} onClick={callback}> + {title} + </Button> </Sneakable> ))} </ButtonRow> @@ -240,6 +247,7 @@ export class NotificationView extends React.PureComponent<INotification, {}> { const { level, buttons } = this.props return ( <NotificationWrapper + data-test="notification" key={this.props.id} onClick={this.props.onClick} className="notification" @@ -258,14 +266,16 @@ export class NotificationView extends React.PureComponent<INotification, {}> { </Sneakable> </NotificationIconWrapper> </IconContainer> - <NotificationTitle level={level}>{this.props.title}</NotificationTitle> + <NotificationTitle data-test="notification-title" level={level}> + {this.props.title} + </NotificationTitle> </NotificationHeader> <NotificationContents> <NotificationDescription className="notification-description"> {this.props.detail} </NotificationDescription> </NotificationContents> - {buttons && <Buttons buttons={buttons} />} + {buttons && <Buttons onClose={this.props.onClose} buttons={buttons} />} </NotificationWrapper> ) } diff --git a/browser/src/Utility.ts b/browser/src/Utility.ts index c496436b87..20f9cf890b 100644 --- a/browser/src/Utility.ts +++ b/browser/src/Utility.ts @@ -245,3 +245,15 @@ export function ignoreWhilePendingPromise<T, U>( return ret } + +export function checkIfFileExistsSync(filename: string): boolean | Error { + try { + return fs.statSync(filename).isFile() + } catch (e) { + if (e.code === "ENOENT") { + return false + } else { + throw e + } + } +} diff --git a/browser/src/neovim/NeovimInstance.ts b/browser/src/neovim/NeovimInstance.ts index 5b3ededa5f..69fd9f2164 100644 --- a/browser/src/neovim/NeovimInstance.ts +++ b/browser/src/neovim/NeovimInstance.ts @@ -14,6 +14,8 @@ import { addDefaultUnitIfNeeded, measureFont } from "./../Font" import * as Platform from "./../Platform" import { Configuration } from "./../Services/Configuration" +import { checkIfFileExistsSync } from "./../Utility" + import * as Actions from "./actions" import { NeovimBufferReference } from "./MsgPack" import { INeovimAutoCommands, NeovimAutoCommands } from "./NeovimAutoCommands" @@ -544,19 +546,44 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { return this.command(`e! ${fileName}`) } + /** + * getInitVimPath + * return the init vim path with no check to ensure existence + */ + public getInitVimPath(): string { + // tslint:disable no-string-literal + const MYVIMRC = process.env["MYVIMRC"] + const rootFolder = Platform.isWindows() + ? // Use path from: https://github.com/neovim/neovim/wiki/FAQ + path.join(process.env["LOCALAPPDATA"], "nvim") + : path.join(Platform.getUserHome(), ".config", "nvim") + const initVimPath = MYVIMRC || path.join(rootFolder, "init.vim") + return initVimPath + // tslint:enable no-string-literal + } + + /** + * doesInitVimExist + * Returns the init.vim path after checking the file exists + */ + public doesInitVimExist(): string { + const initVimPath = this.getInitVimPath() + try { + return checkIfFileExistsSync(initVimPath) ? initVimPath : null + } catch (e) { + return null + } + } + public openInitVim(): Promise<void> { const loadInitVim = this._configuration.getValue("oni.loadInitVim") if (typeof loadInitVim === "string") { return this.open(loadInitVim) } else { - // Use path from: https://github.com/neovim/neovim/wiki/FAQ - const rootFolder = Platform.isWindows() - ? path.join(process.env["LOCALAPPDATA"], "nvim") // tslint:disable-line no-string-literal - : path.join(Platform.getUserHome(), ".config", "nvim") - + const initVimPath = this.getInitVimPath() + const rootFolder = path.dirname(initVimPath) mkdirp.sync(rootFolder) - const initVimPath = path.join(rootFolder, "init.vim") return this.open(initVimPath) } diff --git a/test/CiTests.ts b/test/CiTests.ts index 43540a05c1..c6203e0a0c 100644 --- a/test/CiTests.ts +++ b/test/CiTests.ts @@ -22,6 +22,7 @@ const CiTests = [ "Configuration.TypeScriptEditor.NewConfigurationTest", "Configuration.TypeScriptEditor.CompletionTest", + "initVimPromptNotificationTest", "Editor.BuffersCursorTest", "Editor.ExternalCommandLineTest", "Editor.BufferModifiedState", diff --git a/test/ci/Common.ts b/test/ci/Common.ts index 1c6edb2637..4eb7277428 100644 --- a/test/ci/Common.ts +++ b/test/ci/Common.ts @@ -31,6 +31,9 @@ export const getElementsBySelector = (selector: string) => { return elements || [] } +export const getSingleElementBySelector = (selector: string) => + document.body.querySelector(selector) + export const createNewFile = async ( fileExtension: string, oni: Oni.Plugin.Api, diff --git a/test/ci/initVimPromptNotificationTest.ts b/test/ci/initVimPromptNotificationTest.ts new file mode 100644 index 0000000000..afbaca05de --- /dev/null +++ b/test/ci/initVimPromptNotificationTest.ts @@ -0,0 +1,73 @@ +/** + * initVimPromptNotification Test + * + * Validate that a notification is shown to the user if they have an init.vim + * but are not using it + */ + +// import * as assert from "assert" +import { Assertor } from "./Assert" + +import * as fs from "fs" +import * as Oni from "oni-api" + +import { + createNewFile, + getElementByClassName, + getElementsBySelector, + getSingleElementBySelector, + getTemporaryFilePath, +} from "./Common" + +// tslint:disable:no-console + +const createAndReturnInitVimPath = (): string => { + const tempInitVim = getTemporaryFilePath("vim") + + console.log("- Writing init vim to: " + tempInitVim) + fs.writeFileSync(tempInitVim, "derpInvalidInitVimderp") + console.log("- Write successful.") + + return tempInitVim +} + +export const test = async (oni: Oni.Plugin.Api) => { + const assert = new Assertor("Prompt Notification Test ===============") + await oni.automation.waitForEditors() + + await oni.automation.sleep(1500) + // Grab the notification element on startup + const notification = getSingleElementBySelector("[data-test='notification']") + const notificationTitle = getSingleElementBySelector("[data-test='notification-title']") + + // Validate that the notification element appears + assert.defined(notification, "Notification component exitsts") + assert.defined(notificationTitle, "Notification title exitsts") + + assert.assert( + notificationTitle.textContent.includes("init.vim"), + "Correct notification surfaces", + ) + ;(notification as HTMLElement).click() + + await oni.automation.sleep(2500) + + const isNotification = Boolean(getSingleElementBySelector("[data-test='notification']")) + assert.assert(!isNotification, "The notification disappears") + + const useInitVim = oni.configuration.getValue("oni.loadInitVim") + assert.assert(!useInitVim, "Init vim is disabled") +} + +export const settings = { + env: { + MYVIMRC: createAndReturnInitVimPath(), + }, + config: { + "oni.loadInitVim": false, + "oni.useDefaultConfig": true, + "notifications.enabled": true, + "_internal.hasCheckedInitVim": false, + }, + allowLogFailures: true, +} diff --git a/test/common/Oni.ts b/test/common/Oni.ts index b9926eeae3..719810bb4e 100644 --- a/test/common/Oni.ts +++ b/test/common/Oni.ts @@ -76,7 +76,11 @@ const getArgsForLocalExecution = () => [ ] export interface OniStartOptions { - configurationPath?: string + env?: { + ONI_CONFIG_FILE?: string + MYVIMRC?: string + [key: string]: string + } } export class Oni { @@ -98,7 +102,7 @@ export class Oni { this._app = new Application({ path: executablePath, args: executableArgs, - env: options.configurationPath ? { ONI_CONFIG_FILE: options.configurationPath } : {}, + env: options.env, }) log("Oni starting...") diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index e8d8068c76..851c1f8b5d 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -11,8 +11,10 @@ import { ensureProcessNotRunning } from "./ensureProcessNotRunning" export interface ITestCase { name: string testPath: string - configPath: string allowLogFailures: boolean + env: { + [key: string]: string + } } export interface IFailedTest { @@ -33,8 +35,11 @@ const loadTest = (rootPath: string, testName: string): ITestCase => { const normalizedMeta: ITestCase = { name: testDescription.name || testName, testPath: normalizePath(testPath), - configPath: getConfigPath(testMeta.settings, rootPath), allowLogFailures: testDescription.allowLogFailures, + env: { + ...(testDescription.env || {}), + ONI_CONFIG_FILE: getConfigPath(testMeta.settings, rootPath), + }, } return normalizedMeta @@ -57,7 +62,7 @@ const getConfigPath = (settings: any, rootPath: string) => { // 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({})) + return normalizePath(serializeConfig({ "oni.loadInitVim": false })) } } @@ -111,7 +116,7 @@ export const runInProcTest = ( testCase = loadTest(rootPath, testName) const startOptions = { - configurationPath: testCase.configPath, + env: testCase.env, } oni = new Oni() diff --git a/ui-tests/__snapshots__/NotificationView.test.tsx.snap b/ui-tests/__snapshots__/NotificationView.test.tsx.snap index 5762f4dbb8..a25abc3fae 100644 --- a/ui-tests/__snapshots__/NotificationView.test.tsx.snap +++ b/ui-tests/__snapshots__/NotificationView.test.tsx.snap @@ -3,6 +3,7 @@ exports[`<NotificationsView /> should match the snapshot 1`] = ` <styled.div className="notification" + data-test="notification" key="1" level="info" onClick={[Function]} @@ -35,6 +36,7 @@ exports[`<NotificationsView /> should match the snapshot 1`] = ` </styled.div> </styled.div> <styled.div + data-test="notification-title" level="info" > testing1 From bd8188f6750f79f028b55291525c42280dd730c5 Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Tue, 10 Apr 2018 21:06:22 +0100 Subject: [PATCH 26/59] Bugfix/use max width for tab names (#2074) * use max-width for tab names rather than length check * add tabs snapshot and initial test * add test to check component does not render if visible = false * add classsnames mock file * remove unnecessary with props and fix typo increase max-width a little --- browser/src/UI/components/Tabs.tsx | 23 ++++----- jest.config.js | 1 + ui-tests/Tabs.test.tsx | 60 +++++++++++++++++++++++ ui-tests/__snapshots__/Tabs.test.tsx.snap | 31 ++++++++++++ ui-tests/mocks/classnames.ts | 2 + 5 files changed, 106 insertions(+), 11 deletions(-) create mode 100644 ui-tests/Tabs.test.tsx create mode 100644 ui-tests/__snapshots__/Tabs.test.tsx.snap create mode 100644 ui-tests/mocks/classnames.ts diff --git a/browser/src/UI/components/Tabs.tsx b/browser/src/UI/components/Tabs.tsx index 31f9615f32..d804ee78d2 100644 --- a/browser/src/UI/components/Tabs.tsx +++ b/browser/src/UI/components/Tabs.tsx @@ -17,7 +17,7 @@ import { addDefaultUnitIfNeeded } from "./../../Font" import { Sneakable } from "./../../UI/components/Sneakable" import { Icon } from "./../../UI/Icon" -import { styled, withProps } from "./../components/common" +import { styled } from "./../components/common" import { FileIcon } from "./../../Services/FileIcon" @@ -57,8 +57,8 @@ export interface ITabsProps { fontSize: string } -const InnerName = withProps<{ isLong?: boolean }>(styled.span)` - ${p => p.isLong && `width: 250px;`}; +const InnerName = styled.span` + max-width: 20em; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; @@ -134,13 +134,16 @@ const TabWrapper = styled.div` animation: ${TabEntranceKeyFrames} 0.1s ease-in forwards; ` +interface IChromeDivElement extends HTMLDivElement { + scrollIntoViewIfNeeded: (args: { behavior: string; block: string; inline: string }) => void +} + export class Tab extends React.Component<ITabPropsWithClick> { - private _tab: HTMLDivElement + private _tab: IChromeDivElement public componentWillReceiveProps(next: ITabPropsWithClick) { if (next.isSelected && this._tab) { - const anyTab = this._tab as any - if (anyTab.scrollIntoViewIfNeeded) { - anyTab.scrollIntoViewIfNeeded({ + if (this._tab.scrollIntoViewIfNeeded) { + this._tab.scrollIntoViewIfNeeded({ behavior: "smooth", block: "center", inline: "center", @@ -167,7 +170,7 @@ export class Tab extends React.Component<ITabPropsWithClick> { return ( <Sneakable callback={() => this.props.onClickName()}> <TabWrapper - innerRef={(e: HTMLDivElement) => (this._tab = e)} + innerRef={(e: IChromeDivElement) => (this._tab = e)} className={cssClasses} title={this.props.description} style={style} @@ -180,9 +183,7 @@ export class Tab extends React.Component<ITabPropsWithClick> { /> </div> <div className="name" onClick={this.props.onClickName}> - <InnerName isLong={this.props.name.length > 50}> - {this.props.name} - </InnerName> + <InnerName>{this.props.name}</InnerName> </div> <div className="corner enable-hover" onClick={this.props.onClickClose}> <div className="icon-container x-icon-container"> diff --git a/jest.config.js b/jest.config.js index 0e61f8ab4c..5d0d3713a9 100644 --- a/jest.config.js +++ b/jest.config.js @@ -8,6 +8,7 @@ module.exports = { PersistentSettings: "<rootDir>/ui-tests/mocks/PersistentSettings.ts", Utility: "<rootDir>/ui-tests/mocks/Utility.ts", Configuration: "<rootDir>/ui-tests/mocks/Configuration.ts", + classnames: "<rootDir>/ui-tests/mocks/classnames.ts", }, snapshotSerializers: ["enzyme-to-json/serializer"], transform: { diff --git a/ui-tests/Tabs.test.tsx b/ui-tests/Tabs.test.tsx new file mode 100644 index 0000000000..06740afb43 --- /dev/null +++ b/ui-tests/Tabs.test.tsx @@ -0,0 +1,60 @@ +import { mount, shallow } from "enzyme" +import { shallowToJson } from "enzyme-to-json" +import * as React from "react" + +import { Tab, Tabs } from "../browser/src/UI/components/Tabs" + +describe("<Tabs /> Tests", () => { + const testTabs = [ + { + id: 2, + name: "test", + description: "a test tab", + isSelected: true, + isDirty: true, + iconFileName: "icon", + highlightColor: "#000", + }, + ] + const TestTabs = ( + <Tabs + fontSize="1.2em" + maxWidth="20em" + height="2em" + fontFamily="inherit" + backgroundColor="#fff" + foregroundColor="#000" + shouldWrap={false} + visible={true} + tabs={testTabs} + /> + ) + it("renders without crashing", () => { + const wrapper = shallow(TestTabs) + expect(wrapper.length).toEqual(1) + }) + it("should match last known snapshot unless we make a change", () => { + const wrapper = shallow(TestTabs) + expect(shallowToJson(wrapper)).toMatchSnapshot() + }) + it("Should render the correct number of tabs", () => { + const wrapper = shallow(TestTabs) + expect(wrapper.children.length).toEqual(1) + }) + it("Should not render if the visible prop is false", () => { + const wrapper = shallow( + <Tabs + fontSize="1.2em" + maxWidth="20em" + height="2em" + fontFamily="inherit" + backgroundColor="#fff" + foregroundColor="#000" + shouldWrap={false} + visible={false} + tabs={testTabs} + />, + ) + expect(wrapper.getElement()).toBe(null) + }) +}) diff --git a/ui-tests/__snapshots__/Tabs.test.tsx.snap b/ui-tests/__snapshots__/Tabs.test.tsx.snap new file mode 100644 index 0000000000..ae38c754de --- /dev/null +++ b/ui-tests/__snapshots__/Tabs.test.tsx.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<Tabs /> Tests should match last known snapshot unless we make a change 1`] = ` +<div + className="tabs horizontal enable-mouse layer" + style={ + Object { + "borderBottom": "4px solid #fff", + "fontFamily": "inherit", + "fontSize": "1.2em", + } + } +> + <Tab + backgroundColor="#fff" + description="a test tab" + foregroundColor="#000" + height="2em" + highlightColor="#000" + iconFileName="icon" + id={2} + isDirty={true} + isSelected={true} + key="2" + maxWidth="20em" + name="test" + onClickClose={[Function]} + onClickName={[Function]} + /> +</div> +`; diff --git a/ui-tests/mocks/classnames.ts b/ui-tests/mocks/classnames.ts new file mode 100644 index 0000000000..33abc85533 --- /dev/null +++ b/ui-tests/mocks/classnames.ts @@ -0,0 +1,2 @@ +export default (component: string, classes: { [key: string]: string }) => jest.fn() +export const classNames = jest.fn() From 18faff4b4c8777bdd44d375c5df61135a5a87d5c Mon Sep 17 00:00:00 2001 From: David Duarte <deltaduartedavid@gmail.com> Date: Tue, 10 Apr 2018 23:25:33 +0200 Subject: [PATCH 27/59] Stop propagation of event in File Explorer to avoid multiple click events (#2078) --- browser/src/Services/Explorer/ExplorerView.tsx | 12 +++++++++--- browser/src/UI/components/SidebarItemView.tsx | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index bd30fa83f1..2d1ce179f3 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -42,6 +42,12 @@ const scrollIntoViewIfNeeded = (elem: HTMLElement) => { // tslint:disable-next-line elem && elem["scrollIntoViewIfNeeded"] && elem["scrollIntoViewIfNeeded"]() } +const stopPropagation = (fn: () => void) => { + return (e: React.MouseEvent<HTMLElement>) => { + e.stopPropagation() + fn() + } +} const Types = { FILE: "FILE", @@ -95,7 +101,7 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { isOver={isOver && canDrop} didDrop={didDrop} canDrop={canDrop} - onClick={() => this.props.onClick()} + onClick={stopPropagation(() => this.props.onClick())} text={node.name} isFocused={this.props.isSelected} isContainer={false} @@ -118,7 +124,7 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { isOver={isOver} isContainer={true} isExpanded={node.expanded} - onClick={() => this.props.onClick()} + onClick={stopPropagation(() => this.props.onClick())} text={node.name} isFocused={this.props.isSelected} /> @@ -144,7 +150,7 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { text={node.name} isFocused={this.props.isSelected} indentationLevel={node.indentationLevel} - onClick={() => this.props.onClick()} + onClick={stopPropagation(() => this.props.onClick())} /> ) }} diff --git a/browser/src/UI/components/SidebarItemView.tsx b/browser/src/UI/components/SidebarItemView.tsx index 7e6c695774..7319e7cee7 100644 --- a/browser/src/UI/components/SidebarItemView.tsx +++ b/browser/src/UI/components/SidebarItemView.tsx @@ -19,7 +19,7 @@ export interface ISidebarItemViewProps { isContainer?: boolean indentationLevel: number icon?: JSX.Element - onClick: () => void + onClick: (e: React.MouseEvent<HTMLElement>) => void } const px = (num: number): string => num.toString() + "px" @@ -105,7 +105,7 @@ export interface ISidebarContainerViewProps extends IContainerProps { isFocused: boolean indentationLevel?: number isContainer?: boolean - onClick: () => void + onClick: (e: React.MouseEvent<HTMLElement>) => void } interface IContainerProps { From d9c0ce50310abdf9969e94ef85c73f2d0096c05e Mon Sep 17 00:00:00 2001 From: David Duarte <deltaduartedavid@gmail.com> Date: Thu, 12 Apr 2018 00:44:11 +0200 Subject: [PATCH 28/59] Remove sync calls in ExplorerFileSystem (#2077) * Remove sync calls in ExplorerFileSystem * Mock ExplorerFileSystem --- .../Services/Explorer/ExplorerFileSystem.ts | 31 ++++++++++++------- .../Services/Explorer/ExplorerStoreTests.ts | 28 +++++++++++++++-- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/browser/src/Services/Explorer/ExplorerFileSystem.ts b/browser/src/Services/Explorer/ExplorerFileSystem.ts index 7e4428b29e..82d6379495 100644 --- a/browser/src/Services/Explorer/ExplorerFileSystem.ts +++ b/browser/src/Services/Explorer/ExplorerFileSystem.ts @@ -6,6 +6,7 @@ import * as fs from "fs" import * as path from "path" +import { promisify } from "util" import { FolderOrFile } from "./ExplorerStore" @@ -18,14 +19,26 @@ export interface IFileSystem { } export class FileSystem implements IFileSystem { - constructor(private _fs: typeof fs) {} + private _fs: { + readdir(path: string): Promise<string[]> + stat(path: string): Promise<fs.Stats> + exists(path: string): Promise<boolean> + } + + constructor(nfs: typeof fs) { + this._fs = { + readdir: promisify(nfs.readdir.bind(nfs)), + stat: promisify(nfs.stat.bind(nfs)), + exists: promisify(nfs.exists.bind(nfs)), + } + } - public readdir(directoryPath: string): Promise<FolderOrFile[]> { - const files = this._fs.readdirSync(directoryPath) + public async readdir(directoryPath: string): Promise<FolderOrFile[]> { + const files = await this._fs.readdir(directoryPath) - const filesAndFolders = files.map(f => { + const filesAndFolders = files.map(async f => { const fullPath = path.join(directoryPath, f) - const stat = this._fs.statSync(fullPath) + const stat = await this._fs.stat(fullPath) if (stat.isDirectory()) { return { type: "folder", @@ -39,14 +52,10 @@ export class FileSystem implements IFileSystem { } }) - return Promise.resolve(filesAndFolders) + return Promise.all(filesAndFolders) } public exists(fullPath: string): Promise<boolean> { - return new Promise((resolve, reject) => { - this._fs.exists(fullPath, (exists: boolean) => { - resolve(exists) - }) - }) + return this._fs.exists(fullPath) } } diff --git a/browser/test/Services/Explorer/ExplorerStoreTests.ts b/browser/test/Services/Explorer/ExplorerStoreTests.ts index 8f78a83bf7..5e2b95f873 100644 --- a/browser/test/Services/Explorer/ExplorerStoreTests.ts +++ b/browser/test/Services/Explorer/ExplorerStoreTests.ts @@ -14,9 +14,30 @@ import * as TestHelpers from "./../../TestHelpers" const MemoryFileSystem = require("memory-fs") // tslint:disable-line +export class MockedFileSystem implements ExplorerFileSystem.IFileSystem { + public promises: Array<Promise<any>> + + constructor(private _inner: ExplorerFileSystem.IFileSystem) { + this.promises = [] + } + + public readdir(directoryPath: string): Promise<ExplorerState.FolderOrFile[]> { + const promise = this._inner.readdir(directoryPath) + this.promises.push(promise) + return promise + } + + public exists(fullPath: string): Promise<boolean> { + const promise = this._inner.exists(fullPath) + this.promises.push(promise) + return promise + } +} + describe("ExplorerStore", () => { let fileSystem: any let store: Store<ExplorerState.IExplorerState> + let explorerFileSystem: MockedFileSystem const rootPath = path.normalize(path.join(TestHelpers.getRootDirectory(), "a", "test", "dir")) const filePath = path.join(rootPath, "file.txt") @@ -26,7 +47,9 @@ describe("ExplorerStore", () => { fileSystem.mkdirpSync(rootPath) fileSystem.writeFileSync(filePath, "Hello World") - const explorerFileSystem = new ExplorerFileSystem.FileSystem(fileSystem as any) + explorerFileSystem = new MockedFileSystem( + new ExplorerFileSystem.FileSystem(fileSystem as any), + ) store = ExplorerState.createStore(explorerFileSystem) }) @@ -38,8 +61,9 @@ describe("ExplorerStore", () => { }) await TestHelpers.waitForAllAsyncOperations() + TestHelpers.tick(0) // execute setImmediate of memory-fs callbacks + await Promise.all(explorerFileSystem.promises) - // At this point, the FS operations are synchronous const state = store.getState() assert.deepEqual( From 10056155fa4c8e7069cb8c704b4ca5a5a108890f Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Wed, 11 Apr 2018 17:33:02 -0700 Subject: [PATCH 29/59] Bugfix: Fix markdown preview opening horizontally instead of vertically (#2079) * Fix case where the markdown preview split direction was being ignored * Add failing test * Get test green * Fix lint error --- .../Services/WindowManager/WindowManager.ts | 3 ++- .../WindowManager/WindowManagerTests.ts | 24 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/browser/src/Services/WindowManager/WindowManager.ts b/browser/src/Services/WindowManager/WindowManager.ts index 8a0b98b453..5793f30c11 100644 --- a/browser/src/Services/WindowManager/WindowManager.ts +++ b/browser/src/Services/WindowManager/WindowManager.ts @@ -196,7 +196,8 @@ export class WindowManager { } case "horizontal": case "vertical": - const augmentedRefSplit = this._getAugmentedWindowSplitFromSplit(referenceSplit) + const augmentedRefSplit = + this._getAugmentedWindowSplitFromSplit(referenceSplit) || this.activeSplit this._primarySplit.split(augmentedWindow, splitLocation, augmentedRefSplit) const newState = this._primarySplit.getState() as ISplitInfo<Oni.IWindowSplit> diff --git a/browser/test/Services/WindowManager/WindowManagerTests.ts b/browser/test/Services/WindowManager/WindowManagerTests.ts index 10baead686..1055f0f4b9 100644 --- a/browser/test/Services/WindowManager/WindowManagerTests.ts +++ b/browser/test/Services/WindowManager/WindowManagerTests.ts @@ -4,7 +4,7 @@ import * as assert from "assert" -import { WindowManager } from "./../../../src/Services/WindowManager" +import { ISplitInfo, WindowManager } from "./../../../src/Services/WindowManager" import { MockWindowSplit } from "./../../Mocks" describe("WindowManagerTests", () => { @@ -52,4 +52,26 @@ describe("WindowManagerTests", () => { assert.strictEqual(handle.id, handle3.id) }) + + it("respects direction even if a reference split is not passed in", async () => { + const split1 = new MockWindowSplit("window1") + const split2 = new MockWindowSplit("window2") + + const handle1 = windowManager.createSplit("horizontal", split1) + handle1.focus() + + windowManager.createSplit("vertical", split2, split1) + + const splitRoot = windowManager.splitRoot + + const firstChild = splitRoot.splits[0] as ISplitInfo<MockWindowSplit> + + assert.strictEqual(firstChild.type, "Split") + assert.strictEqual( + firstChild.direction, + "horizontal", + "Validate the splits are arranged horizontally (it's confusing... but this means they are vertical splits)", + ) + assert.strictEqual(firstChild.splits.length, 2, "Validate both windows are in this split") + }) }) From dd7e656fd163a59f2b19c2a7a68a46ae98fb0692 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Sun, 15 Apr 2018 06:37:38 -0700 Subject: [PATCH 30/59] Specify optional 'baseVimBackground' for themes (#2083) * Update solarized theme * Fix background color for solarized * Fix lint issues * Add test * Fix bug when setting colorscheme, where the colorscheme would not always be reported correctly * Remove file accidentally committed --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 33 ++++++++++--- browser/src/Plugins/Api/Oni.ts | 5 +- browser/src/Services/Themes/ThemeManager.ts | 5 ++ .../colors/solarized8_dark.json | 3 +- .../colors/solarized8_dark.vim | 4 -- .../colors/solarized8_light.json | 13 +++--- .../colors/solarized8_light.vim | 4 -- test/CiTests.ts | 2 + test/ci/Theming.LightAndDarkColorsTest.ts | 46 +++++++++++++++++++ 9 files changed, 90 insertions(+), 25 deletions(-) delete mode 100644 extensions/theme-solarized/colors/solarized8_dark.vim delete mode 100644 extensions/theme-solarized/colors/solarized8_light.vim create mode 100644 test/ci/Theming.LightAndDarkColorsTest.ts diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index b550515e37..06e63124cf 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -61,7 +61,7 @@ import { } from "./../../Services/SyntaxHighlighting" import { MenuManager } from "./../../Services/Menu" -import { ThemeManager } from "./../../Services/Themes" +import { IThemeMetadata, ThemeManager } from "./../../Services/Themes" import { TypingPredictionManager } from "./../../Services/TypingPredictionManager" import { Workspace } from "./../../Services/Workspace" @@ -122,6 +122,7 @@ export class NeovimEditor extends Editor implements IEditor { private _windowManager: NeovimWindowManager private _currentColorScheme: string = "" + private _currentBackground: string = "" private _isFirstRender: boolean = true private _lastBufferId: string = null @@ -971,15 +972,17 @@ export class NeovimEditor extends Editor implements IEditor { this._themeManager.onThemeChanged.subscribe(() => { const newTheme = this._themeManager.activeTheme - if (newTheme.baseVimTheme && newTheme.baseVimTheme !== this._currentColorScheme) { - this._neovimInstance.command(":color " + newTheme.baseVimTheme) + if ( + newTheme.baseVimTheme && + (newTheme.baseVimTheme !== this._currentColorScheme || + newTheme.baseVimBackground !== this._currentBackground) + ) { + this.setColorSchemeFromTheme(newTheme) } }) if (this._themeManager.activeTheme && this._themeManager.activeTheme.baseVimTheme) { - await this._neovimInstance.command( - ":color " + this._themeManager.activeTheme.baseVimTheme, - ) + await this.setColorSchemeFromTheme(this._themeManager.activeTheme) } if (filesToOpen && filesToOpen.length > 0) { @@ -998,6 +1001,18 @@ export class NeovimEditor extends Editor implements IEditor { this._scheduleRender() } + public async setColorSchemeFromTheme(theme: IThemeMetadata): Promise<void> { + if ( + (theme.baseVimBackground === "dark" || theme.baseVimBackground === "light") && + theme.baseVimBackground !== this._currentBackground + ) { + await this._neovimInstance.command(":set background=" + theme.baseVimBackground) + this._currentBackground = theme.baseVimBackground + } + + await this._neovimInstance.command(":color " + theme.baseVimTheme) + } + public getBuffers(): Array<Oni.Buffer | Oni.InactiveBuffer> { return this._bufferManager.getBuffers() } @@ -1216,6 +1231,12 @@ export class NeovimEditor extends Editor implements IEditor { private async _onColorsChanged(): Promise<void> { const newColorScheme = await this._neovimInstance.eval<string>("g:colors_name") + + // In error cases, the neovim API layer returns an array + if (typeof newColorScheme !== "string") { + return + } + this._currentColorScheme = newColorScheme const backgroundColor = this._screen.backgroundColor const foregroundColor = this._screen.foregroundColor diff --git a/browser/src/Plugins/Api/Oni.ts b/browser/src/Plugins/Api/Oni.ts index 7c0e52391c..989dee8a16 100644 --- a/browser/src/Plugins/Api/Oni.ts +++ b/browser/src/Plugins/Api/Oni.ts @@ -60,7 +60,6 @@ export class Oni implements OniApi.Plugin.Api { private _dependencies: Dependencies private _ui: Ui private _services: Services - private _colors: Colors public get achievements(): any /* TODO: Promote to API */ { return getAchievementsInstance() @@ -71,7 +70,7 @@ export class Oni implements OniApi.Plugin.Api { } public get colors(): Colors /* TODO: Promote to API */ { - return this._colors + return getColors() } public get commands(): OniApi.Commands.Api { @@ -179,8 +178,6 @@ export class Oni implements OniApi.Plugin.Api { } constructor() { - this._colors = getColors() - this._dependencies = new Dependencies() this._ui = new Ui(react) this._services = new Services() diff --git a/browser/src/Services/Themes/ThemeManager.ts b/browser/src/Services/Themes/ThemeManager.ts index e4843d51d2..9b71d9d513 100644 --- a/browser/src/Services/Themes/ThemeManager.ts +++ b/browser/src/Services/Themes/ThemeManager.ts @@ -283,9 +283,14 @@ export const DefaultThemeColors: IThemeColors = { "editor.tokenColors": [], } +// Value used to determine whether the base Vim theme +// should be set to 'dark' or 'light' +export type VimBackground = "light" | "dark" + export interface IThemeMetadata { name: string baseVimTheme?: string + baseVimBackground?: VimBackground colors: Partial<IThemeColors> tokenColors: TokenColor[] } diff --git a/extensions/theme-solarized/colors/solarized8_dark.json b/extensions/theme-solarized/colors/solarized8_dark.json index ae4229d2fb..68770c38a8 100644 --- a/extensions/theme-solarized/colors/solarized8_dark.json +++ b/extensions/theme-solarized/colors/solarized8_dark.json @@ -1,6 +1,7 @@ { "name": "solarized8_dark", - "baseVimTheme": "solarized8_dark", + "baseVimTheme": "solarized8", + "baseVimBackground": "dark", "colors": { "background": "#073642", "foreground": "#839496", diff --git a/extensions/theme-solarized/colors/solarized8_dark.vim b/extensions/theme-solarized/colors/solarized8_dark.vim deleted file mode 100644 index 7a0022314b..0000000000 --- a/extensions/theme-solarized/colors/solarized8_dark.vim +++ /dev/null @@ -1,4 +0,0 @@ -let s:dir = expand('<sfile>:p:h').(!exists("+shellslash") || &shellslash ? '/' : '\') -set background=dark -execute "source" s:dir."solarized8.vim" -unlet s:dir diff --git a/extensions/theme-solarized/colors/solarized8_light.json b/extensions/theme-solarized/colors/solarized8_light.json index fffd6ec4a8..0fe1fe5549 100644 --- a/extensions/theme-solarized/colors/solarized8_light.json +++ b/extensions/theme-solarized/colors/solarized8_light.json @@ -1,17 +1,18 @@ { "name": "solarized8_light", - "baseVimTheme": "solarized8_light", + "baseVimTheme": "solarized8", + "baseVimBackground": "light", "colors": { - "background": "#073642", + "background": "#eee8d5", "foreground": "#839496", - "title.background": "#002b36", + "title.background": "#eee8d5", "title.foreground": "#839496", - "editor.background": "#002b36", - "editor.foreground": "#586e75", + "editor.background": "#eee8d5", + "editor.foreground": "#839496", - "tabs.background": "#002b36", + "tabs.background": "#eee8d5", "tabs.foreground": "#839496", "toolTip.background": "#002b36", diff --git a/extensions/theme-solarized/colors/solarized8_light.vim b/extensions/theme-solarized/colors/solarized8_light.vim deleted file mode 100644 index 16d8bcc3e3..0000000000 --- a/extensions/theme-solarized/colors/solarized8_light.vim +++ /dev/null @@ -1,4 +0,0 @@ -let s:dir = expand('<sfile>:p:h').(!exists("+shellslash") || &shellslash ? '/' : '\') -set background=light -execute "source" s:dir."solarized8.vim" -unlet s:dir diff --git a/test/CiTests.ts b/test/CiTests.ts index c6203e0a0c..6ace1b9df0 100644 --- a/test/CiTests.ts +++ b/test/CiTests.ts @@ -53,6 +53,8 @@ const CiTests = [ "TextmateHighlighting.ScopesOnEnterTest", "TextmateHighlighting.TokenColorOverrideTest", + "Theming.LightAndDarkColorsTest", + // This test occasionally hangs and breaks tests after - trying to move it later... "LargeFileTest", ] diff --git a/test/ci/Theming.LightAndDarkColorsTest.ts b/test/ci/Theming.LightAndDarkColorsTest.ts new file mode 100644 index 0000000000..33922173db --- /dev/null +++ b/test/ci/Theming.LightAndDarkColorsTest.ts @@ -0,0 +1,46 @@ +/** + * Test script to validate themings are properly set for light/dark versions of theme + */ + +import * as React from "react" + +import * as assert from "assert" +import * as os from "os" +import * as path from "path" + +import * as Oni from "oni-api" + +import { createNewFile } from "./Common" + +const getBackgroundColor = (oni: Oni.Plugin.Api): string => { + return oni.colors.getColor("editor.background") +} + +export const test = async (oni: Oni.Plugin.Api) => { + await oni.automation.waitForEditors() + + // TODO: Should we expose `request` as an API method? + const neovimAsAny: any = oni.editors.activeEditor.neovim + + // Set theme to solarized light, validate background color + oni.configuration.setValues({ "ui.colorscheme": "solarized8_light" }) + await oni.automation.waitFor(() => getBackgroundColor(oni) === "#eee8d5") + + let background: string = await neovimAsAny.request("nvim_get_option", ["background"]) + assert.strictEqual(background, "light") + + // Switch back to dark, validate the color was changed + oni.configuration.setValues({ "ui.colorscheme": "solarized8_dark" }) + await oni.automation.waitFor(() => getBackgroundColor(oni) === "#073642") + + background = await neovimAsAny.request("nvim_get_option", ["background"]) + assert.strictEqual(background, "dark") + + // Switch back to light + oni.configuration.setValues({ "ui.colorscheme": "solarized8_light" }) + await oni.automation.waitFor(() => getBackgroundColor(oni) === "#eee8d5") + background = await neovimAsAny.request("nvim_get_option", ["background"]) + assert.strictEqual(background, "light") + + assert.ok(true, "Color switches were successful!") +} From c91541a77d14ea842292c27bea9f35bcb234ee4d Mon Sep 17 00:00:00 2001 From: Thomas Broadley <buriedunderbooks@hotmail.com> Date: Sun, 15 Apr 2018 09:44:38 -0400 Subject: [PATCH 31/59] docs: fix typo (#2095) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5f608e2cc..55f53d586f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,7 +37,7 @@ Anyone can file an expense. If the expense makes sense for the development of th ### 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. +The primary allotment of our [open collective](https://opencollective.com/oni) budget is dedicated to bounties. Developing features and fixing bugs is a lot 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. From 3c13ad2038e59c8e6529c6e0ad5f26e4222a652f Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Sun, 15 Apr 2018 08:03:28 -0700 Subject: [PATCH 32/59] Align text rendering to vertical pixel boundary (#2090) --- browser/src/Renderer/CanvasRenderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/Renderer/CanvasRenderer.ts b/browser/src/Renderer/CanvasRenderer.ts index 98a8df3187..b6a8687959 100644 --- a/browser/src/Renderer/CanvasRenderer.ts +++ b/browser/src/Renderer/CanvasRenderer.ts @@ -327,7 +327,7 @@ export class CanvasRenderer implements INeovimRenderer { this._canvasContext.fillText( text, boundsStartX, - y * fontHeightInPixels + linePaddingInPixels / 2, + normalizedBoundsY + linePaddingInPixels / 2, ) this._canvasContext.font = lastFontStyle } From c23e28e1aacc47de8d02fe14462a6970d1feb3e8 Mon Sep 17 00:00:00 2001 From: parkerault <engineering@internetparty.io> Date: Sun, 15 Apr 2018 14:27:14 -0500 Subject: [PATCH 33/59] Add Hybrid and Gruvbox themes (#2088) Add a port of the Hybrid theme: https://github.com/w0ng/vim-hybrid ...and also Gruvbox: https://github.com/morhetz/gruvbox --- extensions/theme-gruvbox/colors/gruvbox.vim | 1393 +++++++++++++++++ .../theme-gruvbox/colors/gruvbox_dark.json | 46 + .../theme-gruvbox/colors/gruvbox_light.json | 46 + extensions/theme-gruvbox/package.json | 25 + extensions/theme-hybrid/colors/hybrid.vim | 453 ++++++ .../theme-hybrid/colors/hybrid_dark.json | 46 + .../theme-hybrid/colors/hybrid_light.json | 46 + extensions/theme-hybrid/package.json | 25 + 8 files changed, 2080 insertions(+) create mode 100644 extensions/theme-gruvbox/colors/gruvbox.vim create mode 100644 extensions/theme-gruvbox/colors/gruvbox_dark.json create mode 100644 extensions/theme-gruvbox/colors/gruvbox_light.json create mode 100644 extensions/theme-gruvbox/package.json create mode 100644 extensions/theme-hybrid/colors/hybrid.vim create mode 100644 extensions/theme-hybrid/colors/hybrid_dark.json create mode 100644 extensions/theme-hybrid/colors/hybrid_light.json create mode 100644 extensions/theme-hybrid/package.json diff --git a/extensions/theme-gruvbox/colors/gruvbox.vim b/extensions/theme-gruvbox/colors/gruvbox.vim new file mode 100644 index 0000000000..a0c2c0baa2 --- /dev/null +++ b/extensions/theme-gruvbox/colors/gruvbox.vim @@ -0,0 +1,1393 @@ +" ----------------------------------------------------------------------------- +" File: gruvbox.vim +" Description: Retro groove color scheme for Vim +" Author: morhetz <morhetz@gmail.com> +" Source: https://github.com/morhetz/gruvbox +" Last Modified: 12 Aug 2017 +" ----------------------------------------------------------------------------- + +" Supporting code ------------------------------------------------------------- +" Initialisation: {{{ + +if version > 580 + hi clear + if exists("syntax_on") + syntax reset + endif +endif + +let g:colors_name='gruvbox' + +if !(has('termguicolors') && &termguicolors) && !has('gui_running') && &t_Co != 256 + finish +endif + +" }}} +" Global Settings: {{{ + +if !exists('g:gruvbox_bold') + let g:gruvbox_bold=1 +endif +if !exists('g:gruvbox_italic') + if has('gui_running') || $TERM_ITALICS == 'true' + let g:gruvbox_italic=1 + else + let g:gruvbox_italic=0 + endif +endif +if !exists('g:gruvbox_undercurl') + let g:gruvbox_undercurl=1 +endif +if !exists('g:gruvbox_underline') + let g:gruvbox_underline=1 +endif +if !exists('g:gruvbox_inverse') + let g:gruvbox_inverse=1 +endif + +if !exists('g:gruvbox_guisp_fallback') || index(['fg', 'bg'], g:gruvbox_guisp_fallback) == -1 + let g:gruvbox_guisp_fallback='NONE' +endif + +if !exists('g:gruvbox_improved_strings') + let g:gruvbox_improved_strings=0 +endif + +if !exists('g:gruvbox_improved_warnings') + let g:gruvbox_improved_warnings=0 +endif + +if !exists('g:gruvbox_termcolors') + let g:gruvbox_termcolors=256 +endif + +if !exists('g:gruvbox_invert_indent_guides') + let g:gruvbox_invert_indent_guides=0 +endif + +if exists('g:gruvbox_contrast') + echo 'g:gruvbox_contrast is deprecated; use g:gruvbox_contrast_light and g:gruvbox_contrast_dark instead' +endif + +if !exists('g:gruvbox_contrast_dark') + let g:gruvbox_contrast_dark='medium' +endif + +if !exists('g:gruvbox_contrast_light') + let g:gruvbox_contrast_light='medium' +endif + +let s:is_dark=(&background == 'dark') + +" }}} +" Palette: {{{ + +" setup palette dictionary +let s:gb = {} + +" fill it with absolute colors +let s:gb.dark0_hard = ['#1d2021', 234] " 29-32-33 +let s:gb.dark0 = ['#282828', 235] " 40-40-40 +let s:gb.dark0_soft = ['#32302f', 236] " 50-48-47 +let s:gb.dark1 = ['#3c3836', 237] " 60-56-54 +let s:gb.dark2 = ['#504945', 239] " 80-73-69 +let s:gb.dark3 = ['#665c54', 241] " 102-92-84 +let s:gb.dark4 = ['#7c6f64', 243] " 124-111-100 +let s:gb.dark4_256 = ['#7c6f64', 243] " 124-111-100 + +let s:gb.gray_245 = ['#928374', 245] " 146-131-116 +let s:gb.gray_244 = ['#928374', 244] " 146-131-116 + +let s:gb.light0_hard = ['#f9f5d7', 230] " 249-245-215 +let s:gb.light0 = ['#fbf1c7', 229] " 253-244-193 +let s:gb.light0_soft = ['#f2e5bc', 228] " 242-229-188 +let s:gb.light1 = ['#ebdbb2', 223] " 235-219-178 +let s:gb.light2 = ['#d5c4a1', 250] " 213-196-161 +let s:gb.light3 = ['#bdae93', 248] " 189-174-147 +let s:gb.light4 = ['#a89984', 246] " 168-153-132 +let s:gb.light4_256 = ['#a89984', 246] " 168-153-132 + +let s:gb.bright_red = ['#fb4934', 167] " 251-73-52 +let s:gb.bright_green = ['#b8bb26', 142] " 184-187-38 +let s:gb.bright_yellow = ['#fabd2f', 214] " 250-189-47 +let s:gb.bright_blue = ['#83a598', 109] " 131-165-152 +let s:gb.bright_purple = ['#d3869b', 175] " 211-134-155 +let s:gb.bright_aqua = ['#8ec07c', 108] " 142-192-124 +let s:gb.bright_orange = ['#fe8019', 208] " 254-128-25 + +let s:gb.neutral_red = ['#cc241d', 124] " 204-36-29 +let s:gb.neutral_green = ['#98971a', 106] " 152-151-26 +let s:gb.neutral_yellow = ['#d79921', 172] " 215-153-33 +let s:gb.neutral_blue = ['#458588', 66] " 69-133-136 +let s:gb.neutral_purple = ['#b16286', 132] " 177-98-134 +let s:gb.neutral_aqua = ['#689d6a', 72] " 104-157-106 +let s:gb.neutral_orange = ['#d65d0e', 166] " 214-93-14 + +let s:gb.faded_red = ['#9d0006', 88] " 157-0-6 +let s:gb.faded_green = ['#79740e', 100] " 121-116-14 +let s:gb.faded_yellow = ['#b57614', 136] " 181-118-20 +let s:gb.faded_blue = ['#076678', 24] " 7-102-120 +let s:gb.faded_purple = ['#8f3f71', 96] " 143-63-113 +let s:gb.faded_aqua = ['#427b58', 66] " 66-123-88 +let s:gb.faded_orange = ['#af3a03', 130] " 175-58-3 + +" }}} +" Setup Emphasis: {{{ + +let s:bold = 'bold,' +if g:gruvbox_bold == 0 + let s:bold = '' +endif + +let s:italic = 'italic,' +if g:gruvbox_italic == 0 + let s:italic = '' +endif + +let s:underline = 'underline,' +if g:gruvbox_underline == 0 + let s:underline = '' +endif + +let s:undercurl = 'undercurl,' +if g:gruvbox_undercurl == 0 + let s:undercurl = '' +endif + +let s:inverse = 'inverse,' +if g:gruvbox_inverse == 0 + let s:inverse = '' +endif + +" }}} +" Setup Colors: {{{ + +let s:vim_bg = ['bg', 'bg'] +let s:vim_fg = ['fg', 'fg'] +let s:none = ['NONE', 'NONE'] + +" determine relative colors +if s:is_dark + let s:bg0 = s:gb.dark0 + if g:gruvbox_contrast_dark == 'soft' + let s:bg0 = s:gb.dark0_soft + elseif g:gruvbox_contrast_dark == 'hard' + let s:bg0 = s:gb.dark0_hard + endif + + let s:bg1 = s:gb.dark1 + let s:bg2 = s:gb.dark2 + let s:bg3 = s:gb.dark3 + let s:bg4 = s:gb.dark4 + + let s:gray = s:gb.gray_245 + + let s:fg0 = s:gb.light0 + let s:fg1 = s:gb.light1 + let s:fg2 = s:gb.light2 + let s:fg3 = s:gb.light3 + let s:fg4 = s:gb.light4 + + let s:fg4_256 = s:gb.light4_256 + + let s:red = s:gb.bright_red + let s:green = s:gb.bright_green + let s:yellow = s:gb.bright_yellow + let s:blue = s:gb.bright_blue + let s:purple = s:gb.bright_purple + let s:aqua = s:gb.bright_aqua + let s:orange = s:gb.bright_orange +else + let s:bg0 = s:gb.light0 + if g:gruvbox_contrast_light == 'soft' + let s:bg0 = s:gb.light0_soft + elseif g:gruvbox_contrast_light == 'hard' + let s:bg0 = s:gb.light0_hard + endif + + let s:bg1 = s:gb.light1 + let s:bg2 = s:gb.light2 + let s:bg3 = s:gb.light3 + let s:bg4 = s:gb.light4 + + let s:gray = s:gb.gray_244 + + let s:fg0 = s:gb.dark0 + let s:fg1 = s:gb.dark1 + let s:fg2 = s:gb.dark2 + let s:fg3 = s:gb.dark3 + let s:fg4 = s:gb.dark4 + + let s:fg4_256 = s:gb.dark4_256 + + let s:red = s:gb.faded_red + let s:green = s:gb.faded_green + let s:yellow = s:gb.faded_yellow + let s:blue = s:gb.faded_blue + let s:purple = s:gb.faded_purple + let s:aqua = s:gb.faded_aqua + let s:orange = s:gb.faded_orange +endif + +" reset to 16 colors fallback +if g:gruvbox_termcolors == 16 + let s:bg0[1] = 0 + let s:fg4[1] = 7 + let s:gray[1] = 8 + let s:red[1] = 9 + let s:green[1] = 10 + let s:yellow[1] = 11 + let s:blue[1] = 12 + let s:purple[1] = 13 + let s:aqua[1] = 14 + let s:fg1[1] = 15 +endif + +" save current relative colors back to palette dictionary +let s:gb.bg0 = s:bg0 +let s:gb.bg1 = s:bg1 +let s:gb.bg2 = s:bg2 +let s:gb.bg3 = s:bg3 +let s:gb.bg4 = s:bg4 + +let s:gb.gray = s:gray + +let s:gb.fg0 = s:fg0 +let s:gb.fg1 = s:fg1 +let s:gb.fg2 = s:fg2 +let s:gb.fg3 = s:fg3 +let s:gb.fg4 = s:fg4 + +let s:gb.fg4_256 = s:fg4_256 + +let s:gb.red = s:red +let s:gb.green = s:green +let s:gb.yellow = s:yellow +let s:gb.blue = s:blue +let s:gb.purple = s:purple +let s:gb.aqua = s:aqua +let s:gb.orange = s:orange + +" }}} +" Setup Terminal Colors For Neovim: {{{ + +if has('nvim') + let g:terminal_color_0 = s:bg0[0] + let g:terminal_color_8 = s:gray[0] + + let g:terminal_color_1 = s:gb.neutral_red[0] + let g:terminal_color_9 = s:red[0] + + let g:terminal_color_2 = s:gb.neutral_green[0] + let g:terminal_color_10 = s:green[0] + + let g:terminal_color_3 = s:gb.neutral_yellow[0] + let g:terminal_color_11 = s:yellow[0] + + let g:terminal_color_4 = s:gb.neutral_blue[0] + let g:terminal_color_12 = s:blue[0] + + let g:terminal_color_5 = s:gb.neutral_purple[0] + let g:terminal_color_13 = s:purple[0] + + let g:terminal_color_6 = s:gb.neutral_aqua[0] + let g:terminal_color_14 = s:aqua[0] + + let g:terminal_color_7 = s:fg4[0] + let g:terminal_color_15 = s:fg1[0] +endif + +" }}} +" Overload Setting: {{{ + +let s:hls_cursor = s:orange +if exists('g:gruvbox_hls_cursor') + let s:hls_cursor = get(s:gb, g:gruvbox_hls_cursor) +endif + +let s:number_column = s:none +if exists('g:gruvbox_number_column') + let s:number_column = get(s:gb, g:gruvbox_number_column) +endif + +let s:sign_column = s:bg1 + +if exists('g:gitgutter_override_sign_column_highlight') && + \ g:gitgutter_override_sign_column_highlight == 1 + let s:sign_column = s:number_column +else + let g:gitgutter_override_sign_column_highlight = 0 + + if exists('g:gruvbox_sign_column') + let s:sign_column = get(s:gb, g:gruvbox_sign_column) + endif +endif + +let s:color_column = s:bg1 +if exists('g:gruvbox_color_column') + let s:color_column = get(s:gb, g:gruvbox_color_column) +endif + +let s:vert_split = s:bg0 +if exists('g:gruvbox_vert_split') + let s:vert_split = get(s:gb, g:gruvbox_vert_split) +endif + +let s:invert_signs = '' +if exists('g:gruvbox_invert_signs') + if g:gruvbox_invert_signs == 1 + let s:invert_signs = s:inverse + endif +endif + +let s:invert_selection = s:inverse +if exists('g:gruvbox_invert_selection') + if g:gruvbox_invert_selection == 0 + let s:invert_selection = '' + endif +endif + +let s:invert_tabline = '' +if exists('g:gruvbox_invert_tabline') + if g:gruvbox_invert_tabline == 1 + let s:invert_tabline = s:inverse + endif +endif + +let s:italicize_comments = s:italic +if exists('g:gruvbox_italicize_comments') + if g:gruvbox_italicize_comments == 0 + let s:italicize_comments = '' + endif +endif + +let s:italicize_strings = '' +if exists('g:gruvbox_italicize_strings') + if g:gruvbox_italicize_strings == 1 + let s:italicize_strings = s:italic + endif +endif + +" }}} +" Highlighting Function: {{{ + +function! s:HL(group, fg, ...) + " Arguments: group, guifg, guibg, gui, guisp + + " foreground + let fg = a:fg + + " background + if a:0 >= 1 + let bg = a:1 + else + let bg = s:none + endif + + " emphasis + if a:0 >= 2 && strlen(a:2) + let emstr = a:2 + else + let emstr = 'NONE,' + endif + + " special fallback + if a:0 >= 3 + if g:gruvbox_guisp_fallback != 'NONE' + let fg = a:3 + endif + + " bg fallback mode should invert higlighting + if g:gruvbox_guisp_fallback == 'bg' + let emstr .= 'inverse,' + endif + endif + + let histring = [ 'hi', a:group, + \ 'guifg=' . fg[0], 'ctermfg=' . fg[1], + \ 'guibg=' . bg[0], 'ctermbg=' . bg[1], + \ 'gui=' . emstr[:-2], 'cterm=' . emstr[:-2] + \ ] + + " special + if a:0 >= 3 + call add(histring, 'guisp=' . a:3[0]) + endif + + execute join(histring, ' ') +endfunction + +" }}} +" Gruvbox Hi Groups: {{{ + +" memoize common hi groups +call s:HL('GruvboxFg0', s:fg0) +call s:HL('GruvboxFg1', s:fg1) +call s:HL('GruvboxFg2', s:fg2) +call s:HL('GruvboxFg3', s:fg3) +call s:HL('GruvboxFg4', s:fg4) +call s:HL('GruvboxGray', s:gray) +call s:HL('GruvboxBg0', s:bg0) +call s:HL('GruvboxBg1', s:bg1) +call s:HL('GruvboxBg2', s:bg2) +call s:HL('GruvboxBg3', s:bg3) +call s:HL('GruvboxBg4', s:bg4) + +call s:HL('GruvboxRed', s:red) +call s:HL('GruvboxRedBold', s:red, s:none, s:bold) +call s:HL('GruvboxGreen', s:green) +call s:HL('GruvboxGreenBold', s:green, s:none, s:bold) +call s:HL('GruvboxYellow', s:yellow) +call s:HL('GruvboxYellowBold', s:yellow, s:none, s:bold) +call s:HL('GruvboxBlue', s:blue) +call s:HL('GruvboxBlueBold', s:blue, s:none, s:bold) +call s:HL('GruvboxPurple', s:purple) +call s:HL('GruvboxPurpleBold', s:purple, s:none, s:bold) +call s:HL('GruvboxAqua', s:aqua) +call s:HL('GruvboxAquaBold', s:aqua, s:none, s:bold) +call s:HL('GruvboxOrange', s:orange) +call s:HL('GruvboxOrangeBold', s:orange, s:none, s:bold) + +call s:HL('GruvboxRedSign', s:red, s:sign_column, s:invert_signs) +call s:HL('GruvboxGreenSign', s:green, s:sign_column, s:invert_signs) +call s:HL('GruvboxYellowSign', s:yellow, s:sign_column, s:invert_signs) +call s:HL('GruvboxBlueSign', s:blue, s:sign_column, s:invert_signs) +call s:HL('GruvboxPurpleSign', s:purple, s:sign_column, s:invert_signs) +call s:HL('GruvboxAquaSign', s:aqua, s:sign_column, s:invert_signs) + +" }}} + +" Vanilla colorscheme --------------------------------------------------------- +" General UI: {{{ + +" Normal text +call s:HL('Normal', s:fg1, s:bg0) + +" Correct background (see issue #7): +" --- Problem with changing between dark and light on 256 color terminal +" --- https://github.com/morhetz/gruvbox/issues/7 +if s:is_dark + set background=dark +else + set background=light +endif + +if version >= 700 + " Screen line that the cursor is + call s:HL('CursorLine', s:none, s:bg1) + " Screen column that the cursor is + hi! link CursorColumn CursorLine + + " Tab pages line filler + call s:HL('TabLineFill', s:bg4, s:bg1, s:invert_tabline) + " Active tab page label + call s:HL('TabLineSel', s:green, s:bg1, s:invert_tabline) + " Not active tab page label + hi! link TabLine TabLineFill + + " Match paired bracket under the cursor + call s:HL('MatchParen', s:none, s:bg3, s:bold) +endif + +if version >= 703 + " Highlighted screen columns + call s:HL('ColorColumn', s:none, s:color_column) + + " Concealed element: \lambda → λ + call s:HL('Conceal', s:blue, s:none) + + " Line number of CursorLine + call s:HL('CursorLineNr', s:yellow, s:bg1) +endif + +hi! link NonText GruvboxBg2 +hi! link SpecialKey GruvboxBg2 + +call s:HL('Visual', s:none, s:bg3, s:invert_selection) +hi! link VisualNOS Visual + +call s:HL('Search', s:yellow, s:bg0, s:inverse) +call s:HL('IncSearch', s:hls_cursor, s:bg0, s:inverse) + +call s:HL('Underlined', s:blue, s:none, s:underline) + +call s:HL('StatusLine', s:bg2, s:fg1, s:inverse) +call s:HL('StatusLineNC', s:bg1, s:fg4, s:inverse) + +" The column separating vertically split windows +call s:HL('VertSplit', s:bg3, s:vert_split) + +" Current match in wildmenu completion +call s:HL('WildMenu', s:blue, s:bg2, s:bold) + +" Directory names, special names in listing +hi! link Directory GruvboxGreenBold + +" Titles for output from :set all, :autocmd, etc. +hi! link Title GruvboxGreenBold + +" Error messages on the command line +call s:HL('ErrorMsg', s:bg0, s:red, s:bold) +" More prompt: -- More -- +hi! link MoreMsg GruvboxYellowBold +" Current mode message: -- INSERT -- +hi! link ModeMsg GruvboxYellowBold +" 'Press enter' prompt and yes/no questions +hi! link Question GruvboxOrangeBold +" Warning messages +hi! link WarningMsg GruvboxRedBold + +" }}} +" Gutter: {{{ + +" Line number for :number and :# commands +call s:HL('LineNr', s:bg4, s:number_column) + +" Column where signs are displayed +call s:HL('SignColumn', s:none, s:sign_column) + +" Line used for closed folds +call s:HL('Folded', s:gray, s:bg1, s:italic) +" Column where folds are displayed +call s:HL('FoldColumn', s:gray, s:bg1) + +" }}} +" Cursor: {{{ + +" Character under cursor +call s:HL('Cursor', s:none, s:none, s:inverse) +" Visual mode cursor, selection +hi! link vCursor Cursor +" Input moder cursor +hi! link iCursor Cursor +" Language mapping cursor +hi! link lCursor Cursor + +" }}} +" Syntax Highlighting: {{{ + +if g:gruvbox_improved_strings == 0 + hi! link Special GruvboxOrange +else + call s:HL('Special', s:orange, s:bg1, s:italicize_strings) +endif + +call s:HL('Comment', s:gray, s:none, s:italicize_comments) +call s:HL('Todo', s:vim_fg, s:vim_bg, s:bold . s:italic) +call s:HL('Error', s:red, s:vim_bg, s:bold . s:inverse) + +" Generic statement +hi! link Statement GruvboxRed +" if, then, else, endif, swicth, etc. +hi! link Conditional GruvboxRed +" for, do, while, etc. +hi! link Repeat GruvboxRed +" case, default, etc. +hi! link Label GruvboxRed +" try, catch, throw +hi! link Exception GruvboxRed +" sizeof, "+", "*", etc. +hi! link Operator Normal +" Any other keyword +hi! link Keyword GruvboxRed + +" Variable name +hi! link Identifier GruvboxBlue +" Function name +hi! link Function GruvboxGreenBold + +" Generic preprocessor +hi! link PreProc GruvboxAqua +" Preprocessor #include +hi! link Include GruvboxAqua +" Preprocessor #define +hi! link Define GruvboxAqua +" Same as Define +hi! link Macro GruvboxAqua +" Preprocessor #if, #else, #endif, etc. +hi! link PreCondit GruvboxAqua + +" Generic constant +hi! link Constant GruvboxPurple +" Character constant: 'c', '/n' +hi! link Character GruvboxPurple +" String constant: "this is a string" +if g:gruvbox_improved_strings == 0 + call s:HL('String', s:green, s:none, s:italicize_strings) +else + call s:HL('String', s:fg1, s:bg1, s:italicize_strings) +endif +" Boolean constant: TRUE, false +hi! link Boolean GruvboxPurple +" Number constant: 234, 0xff +hi! link Number GruvboxPurple +" Floating point constant: 2.3e10 +hi! link Float GruvboxPurple + +" Generic type +hi! link Type GruvboxYellow +" static, register, volatile, etc +hi! link StorageClass GruvboxOrange +" struct, union, enum, etc. +hi! link Structure GruvboxAqua +" typedef +hi! link Typedef GruvboxYellow + +" }}} +" Completion Menu: {{{ + +if version >= 700 + " Popup menu: normal item + call s:HL('Pmenu', s:fg1, s:bg2) + " Popup menu: selected item + call s:HL('PmenuSel', s:bg2, s:blue, s:bold) + " Popup menu: scrollbar + call s:HL('PmenuSbar', s:none, s:bg2) + " Popup menu: scrollbar thumb + call s:HL('PmenuThumb', s:none, s:bg4) +endif + +" }}} +" Diffs: {{{ + +call s:HL('DiffDelete', s:red, s:bg0, s:inverse) +call s:HL('DiffAdd', s:green, s:bg0, s:inverse) +"call s:HL('DiffChange', s:bg0, s:blue) +"call s:HL('DiffText', s:bg0, s:yellow) + +" Alternative setting +call s:HL('DiffChange', s:aqua, s:bg0, s:inverse) +call s:HL('DiffText', s:yellow, s:bg0, s:inverse) + +" }}} +" Spelling: {{{ + +if has("spell") + " Not capitalised word, or compile warnings + if g:gruvbox_improved_warnings == 0 + call s:HL('SpellCap', s:none, s:none, s:undercurl, s:red) + else + call s:HL('SpellCap', s:green, s:none, s:bold . s:italic) + endif + " Not recognized word + call s:HL('SpellBad', s:none, s:none, s:undercurl, s:blue) + " Wrong spelling for selected region + call s:HL('SpellLocal', s:none, s:none, s:undercurl, s:aqua) + " Rare word + call s:HL('SpellRare', s:none, s:none, s:undercurl, s:purple) +endif + +" }}} + +" Plugin specific ------------------------------------------------------------- +" EasyMotion: {{{ + +hi! link EasyMotionTarget Search +hi! link EasyMotionShade Comment + +" }}} +" Sneak: {{{ + +hi! link Sneak Search +hi! link SneakLabel Search + +" }}} +" Indent Guides: {{{ + +if !exists('g:indent_guides_auto_colors') + let g:indent_guides_auto_colors = 0 +endif + +if g:indent_guides_auto_colors == 0 + if g:gruvbox_invert_indent_guides == 0 + call s:HL('IndentGuidesOdd', s:vim_bg, s:bg2) + call s:HL('IndentGuidesEven', s:vim_bg, s:bg1) + else + call s:HL('IndentGuidesOdd', s:vim_bg, s:bg2, s:inverse) + call s:HL('IndentGuidesEven', s:vim_bg, s:bg3, s:inverse) + endif +endif + +" }}} +" IndentLine: {{{ + +if !exists('g:indentLine_color_term') + let g:indentLine_color_term = s:bg2[1] +endif +if !exists('g:indentLine_color_gui') + let g:indentLine_color_gui = s:bg2[0] +endif + +" }}} +" Rainbow Parentheses: {{{ + +if !exists('g:rbpt_colorpairs') + let g:rbpt_colorpairs = + \ [ + \ ['blue', '#458588'], ['magenta', '#b16286'], + \ ['red', '#cc241d'], ['166', '#d65d0e'] + \ ] +endif + +let g:rainbow_guifgs = [ '#d65d0e', '#cc241d', '#b16286', '#458588' ] +let g:rainbow_ctermfgs = [ '166', 'red', 'magenta', 'blue' ] + +if !exists('g:rainbow_conf') + let g:rainbow_conf = {} +endif +if !has_key(g:rainbow_conf, 'guifgs') + let g:rainbow_conf['guifgs'] = g:rainbow_guifgs +endif +if !has_key(g:rainbow_conf, 'ctermfgs') + let g:rainbow_conf['ctermfgs'] = g:rainbow_ctermfgs +endif + +let g:niji_dark_colours = g:rbpt_colorpairs +let g:niji_light_colours = g:rbpt_colorpairs + +"}}} +" GitGutter: {{{ + +hi! link GitGutterAdd GruvboxGreenSign +hi! link GitGutterChange GruvboxAquaSign +hi! link GitGutterDelete GruvboxRedSign +hi! link GitGutterChangeDelete GruvboxAquaSign + +" }}} +" GitCommit: "{{{ + +hi! link gitcommitSelectedFile GruvboxGreen +hi! link gitcommitDiscardedFile GruvboxRed + +" }}} +" Signify: {{{ + +hi! link SignifySignAdd GruvboxGreenSign +hi! link SignifySignChange GruvboxAquaSign +hi! link SignifySignDelete GruvboxRedSign + +" }}} +" Syntastic: {{{ + +call s:HL('SyntasticError', s:none, s:none, s:undercurl, s:red) +call s:HL('SyntasticWarning', s:none, s:none, s:undercurl, s:yellow) + +hi! link SyntasticErrorSign GruvboxRedSign +hi! link SyntasticWarningSign GruvboxYellowSign + +" }}} +" Signature: {{{ +hi! link SignatureMarkText GruvboxBlueSign +hi! link SignatureMarkerText GruvboxPurpleSign + +" }}} +" ShowMarks: {{{ + +hi! link ShowMarksHLl GruvboxBlueSign +hi! link ShowMarksHLu GruvboxBlueSign +hi! link ShowMarksHLo GruvboxBlueSign +hi! link ShowMarksHLm GruvboxBlueSign + +" }}} +" CtrlP: {{{ + +hi! link CtrlPMatch GruvboxYellow +hi! link CtrlPNoEntries GruvboxRed +hi! link CtrlPPrtBase GruvboxBg2 +hi! link CtrlPPrtCursor GruvboxBlue +hi! link CtrlPLinePre GruvboxBg2 + +call s:HL('CtrlPMode1', s:blue, s:bg2, s:bold) +call s:HL('CtrlPMode2', s:bg0, s:blue, s:bold) +call s:HL('CtrlPStats', s:fg4, s:bg2, s:bold) + +" }}} +" Startify: {{{ + +hi! link StartifyBracket GruvboxFg3 +hi! link StartifyFile GruvboxFg1 +hi! link StartifyNumber GruvboxBlue +hi! link StartifyPath GruvboxGray +hi! link StartifySlash GruvboxGray +hi! link StartifySection GruvboxYellow +hi! link StartifySpecial GruvboxBg2 +hi! link StartifyHeader GruvboxOrange +hi! link StartifyFooter GruvboxBg2 + +" }}} +" Vimshell: {{{ + +let g:vimshell_escape_colors = [ + \ s:bg4[0], s:red[0], s:green[0], s:yellow[0], + \ s:blue[0], s:purple[0], s:aqua[0], s:fg4[0], + \ s:bg0[0], s:red[0], s:green[0], s:orange[0], + \ s:blue[0], s:purple[0], s:aqua[0], s:fg0[0] + \ ] + +" }}} +" BufTabLine: {{{ + +call s:HL('BufTabLineCurrent', s:bg0, s:fg4) +call s:HL('BufTabLineActive', s:fg4, s:bg2) +call s:HL('BufTabLineHidden', s:bg4, s:bg1) +call s:HL('BufTabLineFill', s:bg0, s:bg0) + +" }}} +" Asynchronous Lint Engine: {{{ + +call s:HL('ALEError', s:none, s:none, s:undercurl, s:red) +call s:HL('ALEWarning', s:none, s:none, s:undercurl, s:yellow) +call s:HL('ALEInfo', s:none, s:none, s:undercurl, s:blue) + +hi! link ALEErrorSign GruvboxRedSign +hi! link ALEWarningSign GruvboxYellowSign +hi! link ALEInfoSign GruvboxBlueSign + +" }}} +" Dirvish: {{{ + +hi! link DirvishPathTail GruvboxAqua +hi! link DirvishArg GruvboxYellow + +" }}} +" Netrw: {{{ + +hi! link netrwDir GruvboxAqua +hi! link netrwClassify GruvboxAqua +hi! link netrwLink GruvboxGray +hi! link netrwSymLink GruvboxFg1 +hi! link netrwExe GruvboxYellow +hi! link netrwComment GruvboxGray +hi! link netrwList GruvboxBlue +hi! link netrwHelpCmd GruvboxAqua +hi! link netrwCmdSep GruvboxFg3 +hi! link netrwVersion GruvboxGreen + +" }}} +" NERDTree: {{{ + +hi! link NERDTreeDir GruvboxAqua +hi! link NERDTreeDirSlash GruvboxAqua + +hi! link NERDTreeOpenable GruvboxOrange +hi! link NERDTreeClosable GruvboxOrange + +hi! link NERDTreeFile GruvboxFg1 +hi! link NERDTreeExecFile GruvboxYellow + +hi! link NERDTreeUp GruvboxGray +hi! link NERDTreeCWD GruvboxGreen +hi! link NERDTreeHelp GruvboxFg1 + +hi! link NERDTreeToggleOn GruvboxGreen +hi! link NERDTreeToggleOff GruvboxRed + +" }}} +" Vim Multiple Cursors: {{{ + +call s:HL('multiple_cursors_cursor', s:none, s:none, s:inverse) +call s:HL('multiple_cursors_visual', s:none, s:bg2) + +" }}} + +" Filetype specific ----------------------------------------------------------- +" Diff: {{{ + +hi! link diffAdded GruvboxGreen +hi! link diffRemoved GruvboxRed +hi! link diffChanged GruvboxAqua + +hi! link diffFile GruvboxOrange +hi! link diffNewFile GruvboxYellow + +hi! link diffLine GruvboxBlue + +" }}} +" Html: {{{ + +hi! link htmlTag GruvboxBlue +hi! link htmlEndTag GruvboxBlue + +hi! link htmlTagName GruvboxAquaBold +hi! link htmlArg GruvboxAqua + +hi! link htmlScriptTag GruvboxPurple +hi! link htmlTagN GruvboxFg1 +hi! link htmlSpecialTagName GruvboxAquaBold + +call s:HL('htmlLink', s:fg4, s:none, s:underline) + +hi! link htmlSpecialChar GruvboxOrange + +call s:HL('htmlBold', s:vim_fg, s:vim_bg, s:bold) +call s:HL('htmlBoldUnderline', s:vim_fg, s:vim_bg, s:bold . s:underline) +call s:HL('htmlBoldItalic', s:vim_fg, s:vim_bg, s:bold . s:italic) +call s:HL('htmlBoldUnderlineItalic', s:vim_fg, s:vim_bg, s:bold . s:underline . s:italic) + +call s:HL('htmlUnderline', s:vim_fg, s:vim_bg, s:underline) +call s:HL('htmlUnderlineItalic', s:vim_fg, s:vim_bg, s:underline . s:italic) +call s:HL('htmlItalic', s:vim_fg, s:vim_bg, s:italic) + +" }}} +" Xml: {{{ + +hi! link xmlTag GruvboxBlue +hi! link xmlEndTag GruvboxBlue +hi! link xmlTagName GruvboxBlue +hi! link xmlEqual GruvboxBlue +hi! link docbkKeyword GruvboxAquaBold + +hi! link xmlDocTypeDecl GruvboxGray +hi! link xmlDocTypeKeyword GruvboxPurple +hi! link xmlCdataStart GruvboxGray +hi! link xmlCdataCdata GruvboxPurple +hi! link dtdFunction GruvboxGray +hi! link dtdTagName GruvboxPurple + +hi! link xmlAttrib GruvboxAqua +hi! link xmlProcessingDelim GruvboxGray +hi! link dtdParamEntityPunct GruvboxGray +hi! link dtdParamEntityDPunct GruvboxGray +hi! link xmlAttribPunct GruvboxGray + +hi! link xmlEntity GruvboxOrange +hi! link xmlEntityPunct GruvboxOrange +" }}} +" Vim: {{{ + +call s:HL('vimCommentTitle', s:fg4_256, s:none, s:bold . s:italicize_comments) + +hi! link vimNotation GruvboxOrange +hi! link vimBracket GruvboxOrange +hi! link vimMapModKey GruvboxOrange +hi! link vimFuncSID GruvboxFg3 +hi! link vimSetSep GruvboxFg3 +hi! link vimSep GruvboxFg3 +hi! link vimContinue GruvboxFg3 + +" }}} +" Clojure: {{{ + +hi! link clojureKeyword GruvboxBlue +hi! link clojureCond GruvboxOrange +hi! link clojureSpecial GruvboxOrange +hi! link clojureDefine GruvboxOrange + +hi! link clojureFunc GruvboxYellow +hi! link clojureRepeat GruvboxYellow +hi! link clojureCharacter GruvboxAqua +hi! link clojureStringEscape GruvboxAqua +hi! link clojureException GruvboxRed + +hi! link clojureRegexp GruvboxAqua +hi! link clojureRegexpEscape GruvboxAqua +call s:HL('clojureRegexpCharClass', s:fg3, s:none, s:bold) +hi! link clojureRegexpMod clojureRegexpCharClass +hi! link clojureRegexpQuantifier clojureRegexpCharClass + +hi! link clojureParen GruvboxFg3 +hi! link clojureAnonArg GruvboxYellow +hi! link clojureVariable GruvboxBlue +hi! link clojureMacro GruvboxOrange + +hi! link clojureMeta GruvboxYellow +hi! link clojureDeref GruvboxYellow +hi! link clojureQuote GruvboxYellow +hi! link clojureUnquote GruvboxYellow + +" }}} +" C: {{{ + +hi! link cOperator GruvboxPurple +hi! link cStructure GruvboxOrange + +" }}} +" Python: {{{ + +hi! link pythonBuiltin GruvboxOrange +hi! link pythonBuiltinObj GruvboxOrange +hi! link pythonBuiltinFunc GruvboxOrange +hi! link pythonFunction GruvboxAqua +hi! link pythonDecorator GruvboxRed +hi! link pythonInclude GruvboxBlue +hi! link pythonImport GruvboxBlue +hi! link pythonRun GruvboxBlue +hi! link pythonCoding GruvboxBlue +hi! link pythonOperator GruvboxRed +hi! link pythonException GruvboxRed +hi! link pythonExceptions GruvboxPurple +hi! link pythonBoolean GruvboxPurple +hi! link pythonDot GruvboxFg3 +hi! link pythonConditional GruvboxRed +hi! link pythonRepeat GruvboxRed +hi! link pythonDottedName GruvboxGreenBold + +" }}} +" CSS: {{{ + +hi! link cssBraces GruvboxBlue +hi! link cssFunctionName GruvboxYellow +hi! link cssIdentifier GruvboxOrange +hi! link cssClassName GruvboxGreen +hi! link cssColor GruvboxBlue +hi! link cssSelectorOp GruvboxBlue +hi! link cssSelectorOp2 GruvboxBlue +hi! link cssImportant GruvboxGreen +hi! link cssVendor GruvboxFg1 + +hi! link cssTextProp GruvboxAqua +hi! link cssAnimationProp GruvboxAqua +hi! link cssUIProp GruvboxYellow +hi! link cssTransformProp GruvboxAqua +hi! link cssTransitionProp GruvboxAqua +hi! link cssPrintProp GruvboxAqua +hi! link cssPositioningProp GruvboxYellow +hi! link cssBoxProp GruvboxAqua +hi! link cssFontDescriptorProp GruvboxAqua +hi! link cssFlexibleBoxProp GruvboxAqua +hi! link cssBorderOutlineProp GruvboxAqua +hi! link cssBackgroundProp GruvboxAqua +hi! link cssMarginProp GruvboxAqua +hi! link cssListProp GruvboxAqua +hi! link cssTableProp GruvboxAqua +hi! link cssFontProp GruvboxAqua +hi! link cssPaddingProp GruvboxAqua +hi! link cssDimensionProp GruvboxAqua +hi! link cssRenderProp GruvboxAqua +hi! link cssColorProp GruvboxAqua +hi! link cssGeneratedContentProp GruvboxAqua + +" }}} +" JavaScript: {{{ + +hi! link javaScriptBraces GruvboxFg1 +hi! link javaScriptFunction GruvboxAqua +hi! link javaScriptIdentifier GruvboxRed +hi! link javaScriptMember GruvboxBlue +hi! link javaScriptNumber GruvboxPurple +hi! link javaScriptNull GruvboxPurple +hi! link javaScriptParens GruvboxFg3 + +" }}} +" YAJS: {{{ + +hi! link javascriptImport GruvboxAqua +hi! link javascriptExport GruvboxAqua +hi! link javascriptClassKeyword GruvboxAqua +hi! link javascriptClassExtends GruvboxAqua +hi! link javascriptDefault GruvboxAqua + +hi! link javascriptClassName GruvboxYellow +hi! link javascriptClassSuperName GruvboxYellow +hi! link javascriptGlobal GruvboxYellow + +hi! link javascriptEndColons GruvboxFg1 +hi! link javascriptFuncArg GruvboxFg1 +hi! link javascriptGlobalMethod GruvboxFg1 +hi! link javascriptNodeGlobal GruvboxFg1 +hi! link javascriptBOMWindowProp GruvboxFg1 +hi! link javascriptArrayMethod GruvboxFg1 +hi! link javascriptArrayStaticMethod GruvboxFg1 +hi! link javascriptCacheMethod GruvboxFg1 +hi! link javascriptDateMethod GruvboxFg1 +hi! link javascriptMathStaticMethod GruvboxFg1 + +" hi! link javascriptProp GruvboxFg1 +hi! link javascriptURLUtilsProp GruvboxFg1 +hi! link javascriptBOMNavigatorProp GruvboxFg1 +hi! link javascriptDOMDocMethod GruvboxFg1 +hi! link javascriptDOMDocProp GruvboxFg1 +hi! link javascriptBOMLocationMethod GruvboxFg1 +hi! link javascriptBOMWindowMethod GruvboxFg1 +hi! link javascriptStringMethod GruvboxFg1 + +hi! link javascriptVariable GruvboxOrange +" hi! link javascriptVariable GruvboxRed +" hi! link javascriptIdentifier GruvboxOrange +" hi! link javascriptClassSuper GruvboxOrange +hi! link javascriptIdentifier GruvboxOrange +hi! link javascriptClassSuper GruvboxOrange + +" hi! link javascriptFuncKeyword GruvboxOrange +" hi! link javascriptAsyncFunc GruvboxOrange +hi! link javascriptFuncKeyword GruvboxAqua +hi! link javascriptAsyncFunc GruvboxAqua +hi! link javascriptClassStatic GruvboxOrange + +hi! link javascriptOperator GruvboxRed +hi! link javascriptForOperator GruvboxRed +hi! link javascriptYield GruvboxRed +hi! link javascriptExceptions GruvboxRed +hi! link javascriptMessage GruvboxRed + +hi! link javascriptTemplateSB GruvboxAqua +hi! link javascriptTemplateSubstitution GruvboxFg1 + +" hi! link javascriptLabel GruvboxBlue +" hi! link javascriptObjectLabel GruvboxBlue +" hi! link javascriptPropertyName GruvboxBlue +hi! link javascriptLabel GruvboxFg1 +hi! link javascriptObjectLabel GruvboxFg1 +hi! link javascriptPropertyName GruvboxFg1 + +hi! link javascriptLogicSymbols GruvboxFg1 +hi! link javascriptArrowFunc GruvboxYellow + +hi! link javascriptDocParamName GruvboxFg4 +hi! link javascriptDocTags GruvboxFg4 +hi! link javascriptDocNotation GruvboxFg4 +hi! link javascriptDocParamType GruvboxFg4 +hi! link javascriptDocNamedParamType GruvboxFg4 + +hi! link javascriptBrackets GruvboxFg1 +hi! link javascriptDOMElemAttrs GruvboxFg1 +hi! link javascriptDOMEventMethod GruvboxFg1 +hi! link javascriptDOMNodeMethod GruvboxFg1 +hi! link javascriptDOMStorageMethod GruvboxFg1 +hi! link javascriptHeadersMethod GruvboxFg1 + +hi! link javascriptAsyncFuncKeyword GruvboxRed +hi! link javascriptAwaitFuncKeyword GruvboxRed + +" }}} +" PanglossJS: {{{ + +hi! link jsClassKeyword GruvboxAqua +hi! link jsExtendsKeyword GruvboxAqua +hi! link jsExportDefault GruvboxAqua +hi! link jsTemplateBraces GruvboxAqua +hi! link jsGlobalNodeObjects GruvboxFg1 +hi! link jsGlobalObjects GruvboxFg1 +hi! link jsFunction GruvboxAqua +hi! link jsFuncParens GruvboxFg3 +hi! link jsParens GruvboxFg3 +hi! link jsNull GruvboxPurple +hi! link jsUndefined GruvboxPurple +hi! link jsClassDefinition GruvboxYellow + +" }}} +" TypeScript: {{{ + +hi! link typeScriptReserved GruvboxAqua +hi! link typeScriptLabel GruvboxAqua +hi! link typeScriptFuncKeyword GruvboxAqua +hi! link typeScriptIdentifier GruvboxOrange +hi! link typeScriptBraces GruvboxFg1 +hi! link typeScriptEndColons GruvboxFg1 +hi! link typeScriptDOMObjects GruvboxFg1 +hi! link typeScriptAjaxMethods GruvboxFg1 +hi! link typeScriptLogicSymbols GruvboxFg1 +hi! link typeScriptDocSeeTag Comment +hi! link typeScriptDocParam Comment +hi! link typeScriptDocTags vimCommentTitle +hi! link typeScriptGlobalObjects GruvboxFg1 +hi! link typeScriptParens GruvboxFg3 +hi! link typeScriptOpSymbols GruvboxFg3 +hi! link typeScriptHtmlElemProperties GruvboxFg1 +hi! link typeScriptNull GruvboxPurple +hi! link typeScriptInterpolationDelimiter GruvboxAqua + +" }}} +" PureScript: {{{ + +hi! link purescriptModuleKeyword GruvboxAqua +hi! link purescriptModuleName GruvboxFg1 +hi! link purescriptWhere GruvboxAqua +hi! link purescriptDelimiter GruvboxFg4 +hi! link purescriptType GruvboxFg1 +hi! link purescriptImportKeyword GruvboxAqua +hi! link purescriptHidingKeyword GruvboxAqua +hi! link purescriptAsKeyword GruvboxAqua +hi! link purescriptStructure GruvboxAqua +hi! link purescriptOperator GruvboxBlue + +hi! link purescriptTypeVar GruvboxFg1 +hi! link purescriptConstructor GruvboxFg1 +hi! link purescriptFunction GruvboxFg1 +hi! link purescriptConditional GruvboxOrange +hi! link purescriptBacktick GruvboxOrange + +" }}} +" CoffeeScript: {{{ + +hi! link coffeeExtendedOp GruvboxFg3 +hi! link coffeeSpecialOp GruvboxFg3 +hi! link coffeeCurly GruvboxOrange +hi! link coffeeParen GruvboxFg3 +hi! link coffeeBracket GruvboxOrange + +" }}} +" Ruby: {{{ + +hi! link rubyStringDelimiter GruvboxGreen +hi! link rubyInterpolationDelimiter GruvboxAqua + +" }}} +" ObjectiveC: {{{ + +hi! link objcTypeModifier GruvboxRed +hi! link objcDirective GruvboxBlue + +" }}} +" Go: {{{ + +hi! link goDirective GruvboxAqua +hi! link goConstants GruvboxPurple +hi! link goDeclaration GruvboxRed +hi! link goDeclType GruvboxBlue +hi! link goBuiltins GruvboxOrange + +" }}} +" Lua: {{{ + +hi! link luaIn GruvboxRed +hi! link luaFunction GruvboxAqua +hi! link luaTable GruvboxOrange + +" }}} +" MoonScript: {{{ + +hi! link moonSpecialOp GruvboxFg3 +hi! link moonExtendedOp GruvboxFg3 +hi! link moonFunction GruvboxFg3 +hi! link moonObject GruvboxYellow + +" }}} +" Java: {{{ + +hi! link javaAnnotation GruvboxBlue +hi! link javaDocTags GruvboxAqua +hi! link javaCommentTitle vimCommentTitle +hi! link javaParen GruvboxFg3 +hi! link javaParen1 GruvboxFg3 +hi! link javaParen2 GruvboxFg3 +hi! link javaParen3 GruvboxFg3 +hi! link javaParen4 GruvboxFg3 +hi! link javaParen5 GruvboxFg3 +hi! link javaOperator GruvboxOrange + +hi! link javaVarArg GruvboxGreen + +" }}} +" Elixir: {{{ + +hi! link elixirDocString Comment + +hi! link elixirStringDelimiter GruvboxGreen +hi! link elixirInterpolationDelimiter GruvboxAqua + +hi! link elixirModuleDeclaration GruvboxYellow + +" }}} +" Scala: {{{ + +" NB: scala vim syntax file is kinda horrible +hi! link scalaNameDefinition GruvboxFg1 +hi! link scalaCaseFollowing GruvboxFg1 +hi! link scalaCapitalWord GruvboxFg1 +hi! link scalaTypeExtension GruvboxFg1 + +hi! link scalaKeyword GruvboxRed +hi! link scalaKeywordModifier GruvboxRed + +hi! link scalaSpecial GruvboxAqua +hi! link scalaOperator GruvboxFg1 + +hi! link scalaTypeDeclaration GruvboxYellow +hi! link scalaTypeTypePostDeclaration GruvboxYellow + +hi! link scalaInstanceDeclaration GruvboxFg1 +hi! link scalaInterpolation GruvboxAqua + +" }}} +" Markdown: {{{ + +call s:HL('markdownItalic', s:fg3, s:none, s:italic) + +hi! link markdownH1 GruvboxGreenBold +hi! link markdownH2 GruvboxGreenBold +hi! link markdownH3 GruvboxYellowBold +hi! link markdownH4 GruvboxYellowBold +hi! link markdownH5 GruvboxYellow +hi! link markdownH6 GruvboxYellow + +hi! link markdownCode GruvboxAqua +hi! link markdownCodeBlock GruvboxAqua +hi! link markdownCodeDelimiter GruvboxAqua + +hi! link markdownBlockquote GruvboxGray +hi! link markdownListMarker GruvboxGray +hi! link markdownOrderedListMarker GruvboxGray +hi! link markdownRule GruvboxGray +hi! link markdownHeadingRule GruvboxGray + +hi! link markdownUrlDelimiter GruvboxFg3 +hi! link markdownLinkDelimiter GruvboxFg3 +hi! link markdownLinkTextDelimiter GruvboxFg3 + +hi! link markdownHeadingDelimiter GruvboxOrange +hi! link markdownUrl GruvboxPurple +hi! link markdownUrlTitleDelimiter GruvboxGreen + +call s:HL('markdownLinkText', s:gray, s:none, s:underline) +hi! link markdownIdDeclaration markdownLinkText + +" }}} +" Haskell: {{{ + +" hi! link haskellType GruvboxYellow +" hi! link haskellOperators GruvboxOrange +" hi! link haskellConditional GruvboxAqua +" hi! link haskellLet GruvboxOrange +" +hi! link haskellType GruvboxFg1 +hi! link haskellIdentifier GruvboxFg1 +hi! link haskellSeparator GruvboxFg1 +hi! link haskellDelimiter GruvboxFg4 +hi! link haskellOperators GruvboxBlue +" +hi! link haskellBacktick GruvboxOrange +hi! link haskellStatement GruvboxOrange +hi! link haskellConditional GruvboxOrange + +hi! link haskellLet GruvboxAqua +hi! link haskellDefault GruvboxAqua +hi! link haskellWhere GruvboxAqua +hi! link haskellBottom GruvboxAqua +hi! link haskellBlockKeywords GruvboxAqua +hi! link haskellImportKeywords GruvboxAqua +hi! link haskellDeclKeyword GruvboxAqua +hi! link haskellDeriving GruvboxAqua +hi! link haskellAssocType GruvboxAqua + +hi! link haskellNumber GruvboxPurple +hi! link haskellPragma GruvboxPurple + +hi! link haskellString GruvboxGreen +hi! link haskellChar GruvboxGreen + +" }}} +" Json: {{{ + +hi! link jsonKeyword GruvboxGreen +hi! link jsonQuote GruvboxGreen +hi! link jsonBraces GruvboxFg1 +hi! link jsonString GruvboxFg1 + +" }}} + + +" Functions ------------------------------------------------------------------- +" Search Highlighting Cursor {{{ + +function! GruvboxHlsShowCursor() + call s:HL('Cursor', s:bg0, s:hls_cursor) +endfunction + +function! GruvboxHlsHideCursor() + call s:HL('Cursor', s:none, s:none, s:inverse) +endfunction + +" }}} + +" vim: set sw=2 ts=2 sts=2 et tw=80 ft=vim fdm=marker: diff --git a/extensions/theme-gruvbox/colors/gruvbox_dark.json b/extensions/theme-gruvbox/colors/gruvbox_dark.json new file mode 100644 index 0000000000..c7db707df4 --- /dev/null +++ b/extensions/theme-gruvbox/colors/gruvbox_dark.json @@ -0,0 +1,46 @@ +{ + "name": "gruvbox_dark", + "baseVimTheme": "gruvbox", + "baseVimBackground": "dark", + "colors": { + "background": "#1d2021", + "foreground": "#ebdbb2", + + "title.background": "#1d2021", + "title.foreground": "#ebdbb2", + + "editor.background": "#282828", + "editor.foreground": "#ebdbb2", + + "tabs.background": "#3c3836", + "tabs.foreground": "#fbf1c7", + + "toolTip.background": "#3c3836", + "toolTip.foreground": "#fbf1c7", + "toolTip.border": "#504945", + + "menu.background": "#3c3836", + "menu.foreground": "#fbf1c7", + "menu.border": "#504945", + + "contextMenu.background": "#3c3836", + "contextMenu.foreground": "#fbf1c7", + "contextMenu.border": "#504945", + "contextMenu.highlight": "#504945", + + "statusBar.background": "#1d2021", + "statusBar.foreground": "#ebdbb2", + + "highlight.mode.insert.background": "#83a598", + "highlight.mode.insert.foreground": "#282828", + + "highlight.mode.normal.background": "#928374", + "highlight.mode.normal.foreground": "#282828", + + "highlight.mode.operator.background": "#d3869b", + "highlight.mode.operator.foreground": "#282828", + + "highlight.mode.visual.background": "#fe8019", + "highlight.mode.visual.foreground": "#282828" + } +} diff --git a/extensions/theme-gruvbox/colors/gruvbox_light.json b/extensions/theme-gruvbox/colors/gruvbox_light.json new file mode 100644 index 0000000000..4aea8c21c4 --- /dev/null +++ b/extensions/theme-gruvbox/colors/gruvbox_light.json @@ -0,0 +1,46 @@ +{ + "name": "gruvbox_light", + "baseVimTheme": "gruvbox", + "baseVimBackground": "light", + "colors": { + "background": "#f9f5d7", + "foreground": "#3c3836", + + "title.background": "#f9f5d7", + "title.foreground": "#3c3836", + + "editor.background": "#fbf1c7", + "editor.foreground": "#3c3836", + + "tabs.background": "#ebdbb2", + "tabs.foreground": "#282828", + + "toolTip.background": "#fbf1c7", + "toolTip.foreground": "#282828", + "toolTip.border": "#d5c4a1", + + "menu.background": "#fbf1c7", + "menu.foreground": "#282828", + "menu.border": "#d5c4a1", + + "contextMenu.background": "#fbf1c7", + "contextMenu.foreground": "#282828", + "contextMenu.border": "#d5c4a1", + "contextMenu.highlight": "#d5c4a1", + + "statusBar.background": "#f9f5d7", + "statusBar.foreground": "#3c3836", + + "highlight.mode.insert.background": "#076678", + "highlight.mode.insert.foreground": "#fbf1c7", + + "highlight.mode.normal.background": "#928374", + "highlight.mode.normal.foreground": "#fbf1c7", + + "highlight.mode.operator.background": "#8f3f71", + "highlight.mode.operator.foreground": "#fbf1c7", + + "highlight.mode.visual.background": "#d65d0e", + "highlight.mode.visual.foreground": "#fbf1c7" + } +} diff --git a/extensions/theme-gruvbox/package.json b/extensions/theme-gruvbox/package.json new file mode 100644 index 0000000000..692234874e --- /dev/null +++ b/extensions/theme-gruvbox/package.json @@ -0,0 +1,25 @@ +{ + "name": "onivim-theme-gruvbox", + "version": "0.0.1", + "description": "Gruvbox theme, ported to Oni", + "engines": { + "oni": "0.3.2" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "contributes": { + "themes": [ + { + "name": "gruvbox_dark", + "path": "colors/gruvbox_dark.json" + }, + { + "name": "gruvbox_light", + "path": "colors/gruvbox_light.json" + } + ] + }, + "author": "Parker Ault", + "license": "MIT" +} diff --git a/extensions/theme-hybrid/colors/hybrid.vim b/extensions/theme-hybrid/colors/hybrid.vim new file mode 100644 index 0000000000..21f020a5c6 --- /dev/null +++ b/extensions/theme-hybrid/colors/hybrid.vim @@ -0,0 +1,453 @@ +" File: hybrid.vim +" Maintainer: Andrew Wong (w0ng) +" URL: https://github.com/w0ng/vim-hybrid +" Modified: 27 Jan 2013 07:33 AM AEST +" License: MIT + +" Description:"{{{ +" ---------------------------------------------------------------------------- +" The default RGB colour palette is taken from Tomorrow-Night.vim: +" https://github.com/chriskempson/vim-tomorrow-theme +" +" The reduced RGB colour palette is taken from Codecademy's online editor: +" https://www.codecademy.com/learn +" +" The syntax highlighting scheme is taken from jellybeans.vim: +" https://github.com/nanotech/jellybeans.vim +" +" The is code taken from solarized.vim: +" https://github.com/altercation/vim-colors-solarized + +"}}} +" Requirements And Recommendations:"{{{ +" ---------------------------------------------------------------------------- +" Requirements +" - gVim 7.3+ on Linux, Mac and Windows. +" - Vim 7.3+ on Linux and Mac, using a terminal that supports 256 colours. +" +" Due to the limited 256 palette, colours in Vim and gVim will still be slightly +" different. +" +" In order to have Vim use the same colours as gVim (the way this colour scheme +" is intended), it is recommended that you define the basic 16 colours in your +" terminal. +" +" For Linux users (rxvt-unicode, xterm): +" +" 1. Add the default palette to ~/.Xresources: +" +" https://gist.github.com/3278077 +" +" or alternatively, add the reduced contrast palette to ~/.Xresources: +" +" https://gist.github.com/w0ng/16e33902508b4a0350ae +" +" 2. Add to ~/.vimrc: +" +" let g:hybrid_custom_term_colors = 1 +" let g:hybrid_reduced_contrast = 1 " Remove this line if using the default palette. +" colorscheme hybrid +" +" For OSX users (iTerm): +" +" 1. Import the default colour preset into iTerm: +" +" https://raw.githubusercontent.com/w0ng/dotfiles/master/iterm2/hybrid.itermcolors +" +" or alternatively, import the reduced contrast color preset into iTerm: +" +" https://raw.githubusercontent.com/w0ng/dotfiles/master/iterm2/hybrid-reduced-contrast.itermcolors +" +" 2. Add to ~/.vimrc: +" +" let g:hybrid_custom_term_colors = 1 +" let g:hybrid_reduced_contrast = 1 " Remove this line if using the default palette. +" colorscheme hybrid + +"}}} +" Initialisation:"{{{ +" ---------------------------------------------------------------------------- + +hi clear + +if exists("syntax_on") + syntax reset +endif + +let s:style = &background + +let g:colors_name = "hybrid" + +"}}} +" GUI And Cterm Palettes:"{{{ +" ---------------------------------------------------------------------------- + +let s:palette = {'gui' : {} , 'cterm' : {}} + +if exists("g:hybrid_reduced_contrast") && g:hybrid_reduced_contrast == 1 + let s:gui_background = "#232c31" + let s:gui_selection = "#425059" + let s:gui_line = "#2d3c46" + let s:gui_comment = "#6c7a80" +else + let s:gui_background = "#1d1f21" + let s:gui_selection = "#373b41" + let s:gui_line = "#282a2e" + let s:gui_comment = "#707880" +endif + +let s:palette.gui.background = { 'dark' : s:gui_background , 'light' : "#e4e4e4" } +let s:palette.gui.foreground = { 'dark' : "#c5c8c6" , 'light' : "#000000" } +let s:palette.gui.selection = { 'dark' : s:gui_selection , 'light' : "#bcbcbc" } +let s:palette.gui.line = { 'dark' : s:gui_line , 'light' : "#d0d0d0" } +let s:palette.gui.comment = { 'dark' : s:gui_comment , 'light' : "#5f5f5f" } +let s:palette.gui.red = { 'dark' : "#cc6666" , 'light' : "#5f0000" } +let s:palette.gui.orange = { 'dark' : "#de935f" , 'light' : "#875f00" } +let s:palette.gui.yellow = { 'dark' : "#f0c674" , 'light' : "#5f5f00" } +let s:palette.gui.green = { 'dark' : "#b5bd68" , 'light' : "#005f00" } +let s:palette.gui.aqua = { 'dark' : "#8abeb7" , 'light' : "#005f5f" } +let s:palette.gui.blue = { 'dark' : "#81a2be" , 'light' : "#00005f" } +let s:palette.gui.purple = { 'dark' : "#b294bb" , 'light' : "#5f005f" } +let s:palette.gui.window = { 'dark' : "#303030" , 'light' : "#9e9e9e" } +let s:palette.gui.darkcolumn = { 'dark' : "#1c1c1c" , 'light' : "#808080" } +let s:palette.gui.addbg = { 'dark' : "#5F875F" , 'light' : "#d7ffd7" } +let s:palette.gui.addfg = { 'dark' : "#d7ffaf" , 'light' : "#005f00" } +let s:palette.gui.changebg = { 'dark' : "#5F5F87" , 'light' : "#d7d7ff" } +let s:palette.gui.changefg = { 'dark' : "#d7d7ff" , 'light' : "#5f005f" } +let s:palette.gui.delbg = { 'dark' : "#cc6666" , 'light' : "#ffd7d7" } +let s:palette.gui.darkblue = { 'dark' : "#00005f" , 'light' : "#d7ffd7" } +let s:palette.gui.darkcyan = { 'dark' : "#005f5f" , 'light' : "#005f00" } +let s:palette.gui.darkred = { 'dark' : "#5f0000" , 'light' : "#d7d7ff" } +let s:palette.gui.darkpurple = { 'dark' : "#5f005f" , 'light' : "#5f005f" } + +if exists("g:hybrid_custom_term_colors") && g:hybrid_custom_term_colors == 1 + let s:cterm_foreground = "15" " White + let s:cterm_selection = "8" " DarkGrey + let s:cterm_line = "0" " Black + let s:cterm_comment = "7" " LightGrey + let s:cterm_red = "9" " LightRed + let s:cterm_orange = "3" " DarkYellow + let s:cterm_yellow = "11" " LightYellow + let s:cterm_green = "10" " LightGreen + let s:cterm_aqua = "14" " LightCyan + let s:cterm_blue = "12" " LightBlue + let s:cterm_purple = "13" " LightMagenta + let s:cterm_delbg = "9" " LightRed +else + let s:cterm_foreground = "250" + let s:cterm_selection = "237" + let s:cterm_line = "235" + let s:cterm_comment = "243" + let s:cterm_red = "167" + let s:cterm_orange = "173" + let s:cterm_yellow = "221" + let s:cterm_green = "143" + let s:cterm_aqua = "109" + let s:cterm_blue = "110" + let s:cterm_purple = "139" + let s:cterm_delbg = "167" +endif + +let s:palette.cterm.background = { 'dark' : "234" , 'light' : "254" } +let s:palette.cterm.foreground = { 'dark' : s:cterm_foreground , 'light' : "16" } +let s:palette.cterm.window = { 'dark' : "236" , 'light' : "247" } +let s:palette.cterm.selection = { 'dark' : s:cterm_selection , 'light' : "250" } +let s:palette.cterm.line = { 'dark' : s:cterm_line , 'light' : "252" } +let s:palette.cterm.comment = { 'dark' : s:cterm_comment , 'light' : "59" } +let s:palette.cterm.red = { 'dark' : s:cterm_red , 'light' : "52" } +let s:palette.cterm.orange = { 'dark' : s:cterm_orange , 'light' : "94" } +let s:palette.cterm.yellow = { 'dark' : s:cterm_yellow , 'light' : "58" } +let s:palette.cterm.green = { 'dark' : s:cterm_green , 'light' : "22" } +let s:palette.cterm.aqua = { 'dark' : s:cterm_aqua , 'light' : "23" } +let s:palette.cterm.blue = { 'dark' : s:cterm_blue , 'light' : "17" } +let s:palette.cterm.purple = { 'dark' : s:cterm_purple , 'light' : "53" } +let s:palette.cterm.darkcolumn = { 'dark' : "234" , 'light' : "244" } +let s:palette.cterm.addbg = { 'dark' : "65" , 'light' : "194" } +let s:palette.cterm.addfg = { 'dark' : "193" , 'light' : "22" } +let s:palette.cterm.changebg = { 'dark' : "60" , 'light' : "189" } +let s:palette.cterm.changefg = { 'dark' : "189" , 'light' : "53" } +let s:palette.cterm.delbg = { 'dark' : s:cterm_delbg , 'light' : "224" } +let s:palette.cterm.darkblue = { 'dark' : "17" , 'light' : "194" } +let s:palette.cterm.darkcyan = { 'dark' : "24" , 'light' : "22" } +let s:palette.cterm.darkred = { 'dark' : "52" , 'light' : "189" } +let s:palette.cterm.darkpurple = { 'dark' : "53" , 'light' : "53" } + +"}}} +" Formatting Options:"{{{ +" ---------------------------------------------------------------------------- +let s:none = "NONE" +let s:t_none = "NONE" +let s:n = "NONE" +let s:c = ",undercurl" +let s:r = ",reverse" +let s:s = ",standout" +let s:b = ",bold" +let s:u = ",underline" +let s:i = ",italic" + +"}}} +" Highlighting Primitives:"{{{ +" ---------------------------------------------------------------------------- +function! s:build_prim(hi_elem, field) + " Given a:hi_elem = bg, a:field = comment + let l:vname = "s:" . a:hi_elem . "_" . a:field " s:bg_comment + let l:gui_assign = "gui".a:hi_elem."=".s:palette.gui[a:field][s:style] " guibg=... + let l:cterm_assign = "cterm".a:hi_elem."=".s:palette.cterm[a:field][s:style] " ctermbg=... + exe "let " . l:vname . " = ' " . l:gui_assign . " " . l:cterm_assign . "'" +endfunction + +let s:bg_none = ' guibg=NONE ctermbg=NONE' +call s:build_prim('bg', 'foreground') +call s:build_prim('bg', 'background') +call s:build_prim('bg', 'selection') +call s:build_prim('bg', 'line') +call s:build_prim('bg', 'comment') +call s:build_prim('bg', 'red') +call s:build_prim('bg', 'orange') +call s:build_prim('bg', 'yellow') +call s:build_prim('bg', 'green') +call s:build_prim('bg', 'aqua') +call s:build_prim('bg', 'blue') +call s:build_prim('bg', 'purple') +call s:build_prim('bg', 'window') +call s:build_prim('bg', 'darkcolumn') +call s:build_prim('bg', 'addbg') +call s:build_prim('bg', 'addfg') +call s:build_prim('bg', 'changebg') +call s:build_prim('bg', 'changefg') +call s:build_prim('bg', 'delbg') +call s:build_prim('bg', 'darkblue') +call s:build_prim('bg', 'darkcyan') +call s:build_prim('bg', 'darkred') +call s:build_prim('bg', 'darkpurple') + +let s:fg_none = ' guifg=NONE ctermfg=NONE' +call s:build_prim('fg', 'foreground') +call s:build_prim('fg', 'background') +call s:build_prim('fg', 'selection') +call s:build_prim('fg', 'line') +call s:build_prim('fg', 'comment') +call s:build_prim('fg', 'red') +call s:build_prim('fg', 'orange') +call s:build_prim('fg', 'yellow') +call s:build_prim('fg', 'green') +call s:build_prim('fg', 'aqua') +call s:build_prim('fg', 'blue') +call s:build_prim('fg', 'purple') +call s:build_prim('fg', 'window') +call s:build_prim('fg', 'darkcolumn') +call s:build_prim('fg', 'addbg') +call s:build_prim('fg', 'addfg') +call s:build_prim('fg', 'changebg') +call s:build_prim('fg', 'changefg') +call s:build_prim('fg', 'darkblue') +call s:build_prim('fg', 'darkcyan') +call s:build_prim('fg', 'darkred') +call s:build_prim('fg', 'darkpurple') + +exe "let s:fmt_none = ' gui=NONE". " cterm=NONE". " term=NONE" ."'" +exe "let s:fmt_bold = ' gui=NONE".s:b. " cterm=NONE".s:b. " term=NONE".s:b ."'" +exe "let s:fmt_bldi = ' gui=NONE".s:b. " cterm=NONE".s:b. " term=NONE".s:b ."'" +exe "let s:fmt_undr = ' gui=NONE".s:u. " cterm=NONE".s:u. " term=NONE".s:u ."'" +exe "let s:fmt_undb = ' gui=NONE".s:u.s:b. " cterm=NONE".s:u.s:b. " term=NONE".s:u.s:b."'" +exe "let s:fmt_undi = ' gui=NONE".s:u. " cterm=NONE".s:u. " term=NONE".s:u ."'" +exe "let s:fmt_curl = ' gui=NONE".s:c. " cterm=NONE".s:c. " term=NONE".s:c ."'" +exe "let s:fmt_ital = ' gui=NONE".s:i. " cterm=NONE".s:i. " term=NONE".s:i ."'" +exe "let s:fmt_stnd = ' gui=NONE".s:s. " cterm=NONE".s:s. " term=NONE".s:s ."'" +exe "let s:fmt_revr = ' gui=NONE".s:r. " cterm=NONE".s:r. " term=NONE".s:r ."'" +exe "let s:fmt_revb = ' gui=NONE".s:r.s:b. " cterm=NONE".s:r.s:b. " term=NONE".s:r.s:b."'" + +exe "let s:sp_none = ' guisp=". s:none ."'" +exe "let s:sp_foreground = ' guisp=". s:palette.gui.foreground[s:style] ."'" +exe "let s:sp_background = ' guisp=". s:palette.gui.background[s:style] ."'" +exe "let s:sp_selection = ' guisp=". s:palette.gui.selection[s:style] ."'" +exe "let s:sp_line = ' guisp=". s:palette.gui.line[s:style] ."'" +exe "let s:sp_comment = ' guisp=". s:palette.gui.comment[s:style] ."'" +exe "let s:sp_red = ' guisp=". s:palette.gui.red[s:style] ."'" +exe "let s:sp_orange = ' guisp=". s:palette.gui.orange[s:style] ."'" +exe "let s:sp_yellow = ' guisp=". s:palette.gui.yellow[s:style] ."'" +exe "let s:sp_green = ' guisp=". s:palette.gui.green[s:style] ."'" +exe "let s:sp_aqua = ' guisp=". s:palette.gui.aqua[s:style] ."'" +exe "let s:sp_blue = ' guisp=". s:palette.gui.blue[s:style] ."'" +exe "let s:sp_purple = ' guisp=". s:palette.gui.purple[s:style] ."'" +exe "let s:sp_window = ' guisp=". s:palette.gui.window[s:style] ."'" +exe "let s:sp_addbg = ' guisp=". s:palette.gui.addbg[s:style] ."'" +exe "let s:sp_addfg = ' guisp=". s:palette.gui.addfg[s:style] ."'" +exe "let s:sp_changebg = ' guisp=". s:palette.gui.changebg[s:style] ."'" +exe "let s:sp_changefg = ' guisp=". s:palette.gui.changefg[s:style] ."'" +exe "let s:sp_darkblue = ' guisp=". s:palette.gui.darkblue[s:style] ."'" +exe "let s:sp_darkcyan = ' guisp=". s:palette.gui.darkcyan[s:style] ."'" +exe "let s:sp_darkred = ' guisp=". s:palette.gui.darkred[s:style] ."'" +exe "let s:sp_darkpurple = ' guisp=". s:palette.gui.darkpurple[s:style] ."'" + +"}}} +" Vim Highlighting: (see :help highlight-groups)"{{{ +" ---------------------------------------------------------------------------- +exe "hi! ColorColumn" .s:fg_none .s:bg_line .s:fmt_none +" Conceal" +" Cursor" +" CursorIM" +exe "hi! CursorColumn" .s:fg_none .s:bg_line .s:fmt_none +exe "hi! CursorLine" .s:fg_none .s:bg_line .s:fmt_none +exe "hi! Directory" .s:fg_blue .s:bg_none .s:fmt_none +exe "hi! DiffAdd" .s:fg_addfg .s:bg_addbg .s:fmt_none +exe "hi! DiffChange" .s:fg_changefg .s:bg_changebg .s:fmt_none +exe "hi! DiffDelete" .s:fg_background .s:bg_delbg .s:fmt_none +exe "hi! DiffText" .s:fg_background .s:bg_blue .s:fmt_none +exe "hi! ErrorMsg" .s:fg_background .s:bg_red .s:fmt_stnd +exe "hi! VertSplit" .s:fg_window .s:bg_none .s:fmt_none +exe "hi! Folded" .s:fg_comment .s:bg_darkcolumn .s:fmt_none +exe "hi! FoldColumn" .s:fg_none .s:bg_darkcolumn .s:fmt_none +exe "hi! SignColumn" .s:fg_none .s:bg_darkcolumn .s:fmt_none +" Incsearch" +exe "hi! LineNr" .s:fg_selection .s:bg_none .s:fmt_none +exe "hi! CursorLineNr" .s:fg_yellow .s:bg_none .s:fmt_none +exe "hi! MatchParen" .s:fg_background .s:bg_changebg .s:fmt_none +exe "hi! ModeMsg" .s:fg_green .s:bg_none .s:fmt_none +exe "hi! MoreMsg" .s:fg_green .s:bg_none .s:fmt_none +exe "hi! NonText" .s:fg_selection .s:bg_none .s:fmt_none +exe "hi! Pmenu" .s:fg_foreground .s:bg_selection .s:fmt_none +exe "hi! PmenuSel" .s:fg_foreground .s:bg_selection .s:fmt_revr +" PmenuSbar" +" PmenuThumb" +exe "hi! Question" .s:fg_green .s:bg_none .s:fmt_none +exe "hi! Search" .s:fg_background .s:bg_yellow .s:fmt_none +exe "hi! SpecialKey" .s:fg_selection .s:bg_none .s:fmt_none +exe "hi! SpellCap" .s:fg_blue .s:bg_darkblue .s:fmt_undr +exe "hi! SpellLocal" .s:fg_aqua .s:bg_darkcyan .s:fmt_undr +exe "hi! SpellBad" .s:fg_red .s:bg_darkred .s:fmt_undr +exe "hi! SpellRare" .s:fg_purple .s:bg_darkpurple .s:fmt_undr +exe "hi! StatusLine" .s:fg_comment .s:bg_background .s:fmt_revr +exe "hi! StatusLineNC" .s:fg_window .s:bg_comment .s:fmt_revr +exe "hi! TabLine" .s:fg_foreground .s:bg_darkcolumn .s:fmt_revr +" TabLineFill" +" TabLineSel" +exe "hi! Title" .s:fg_yellow .s:bg_none .s:fmt_none +exe "hi! Visual" .s:fg_none .s:bg_selection .s:fmt_none +" VisualNos" +exe "hi! WarningMsg" .s:fg_red .s:bg_none .s:fmt_none +" FIXME LongLineWarning to use variables instead of hardcoding +hi LongLineWarning guifg=NONE guibg=#371F1C gui=underline ctermfg=NONE ctermbg=NONE cterm=underline +" WildMenu" + +" Use defined custom background colour for terminal Vim. +if !has('gui_running') && exists("g:hybrid_custom_term_colors") && g:hybrid_custom_term_colors == 1 + let s:bg_normal = s:bg_none +else + let s:bg_normal = s:bg_background +endif +exe "hi! Normal" .s:fg_foreground .s:bg_normal .s:fmt_none + +"}}} +" Generic Syntax Highlighting: (see :help group-name)"{{{ +" ---------------------------------------------------------------------------- +exe "hi! Comment" .s:fg_comment .s:bg_none .s:fmt_none + +exe "hi! Constant" .s:fg_red .s:bg_none .s:fmt_none +exe "hi! String" .s:fg_green .s:bg_none .s:fmt_none +" Character" +" Number" +" Boolean" +" Float" + +exe "hi! Identifier" .s:fg_purple .s:bg_none .s:fmt_none +exe "hi! Function" .s:fg_yellow .s:bg_none .s:fmt_none + +exe "hi! Statement" .s:fg_blue .s:bg_none .s:fmt_none +" Conditional" +" Repeat" +" Label" +exe "hi! Operator" .s:fg_aqua .s:bg_none .s:fmt_none +" Keyword" +" Exception" + +exe "hi! PreProc" .s:fg_aqua .s:bg_none .s:fmt_none +" Include" +" Define" +" Macro" +" PreCondit" + +exe "hi! Type" .s:fg_orange .s:bg_none .s:fmt_none +" StorageClass" +exe "hi! Structure" .s:fg_aqua .s:bg_none .s:fmt_none +" Typedef" + +exe "hi! Special" .s:fg_green .s:bg_none .s:fmt_none +" SpecialChar" +" Tag" +" Delimiter" +" SpecialComment" +" Debug" +" +exe "hi! Underlined" .s:fg_blue .s:bg_none .s:fmt_none + +exe "hi! Ignore" .s:fg_none .s:bg_none .s:fmt_none + +exe "hi! Error" .s:fg_red .s:bg_darkred .s:fmt_undr + +exe "hi! Todo" .s:fg_addfg .s:bg_none .s:fmt_none + +" Quickfix window highlighting +exe "hi! qfLineNr" .s:fg_yellow .s:bg_none .s:fmt_none +" qfFileName" +" qfLineNr" +" qfError" + +"}}} +" Diff Syntax Highlighting:"{{{ +" ---------------------------------------------------------------------------- +" Diff +" diffOldFile +" diffNewFile +" diffFile +" diffOnly +" diffIdentical +" diffDiffer +" diffBDiffer +" diffIsA +" diffNoEOL +" diffCommon +hi! link diffRemoved Constant +" diffChanged +hi! link diffAdded Special +" diffLine +" diffSubname +" diffComment + +"}}} +" +" This is needed for some reason: {{{ + +let &background = s:style + +" }}} +" Legal:"{{{ +" ---------------------------------------------------------------------------- +" Copyright (c) 2011 Ethan Schoonover +" Copyright (c) 2009-2012 NanoTech +" Copyright (c) 2012 w0ng +" +" Permission is hereby granted, free of charge, to any per‐ +" son obtaining a copy of this software and associated doc‐ +" umentation files (the “Software”), to deal in the Soft‐ +" ware without restriction, including without limitation +" the rights to use, copy, modify, merge, publish, distrib‐ +" ute, sublicense, and/or sell copies of the Software, and +" to permit persons to whom the Software is furnished to do +" so, subject to the following conditions: +" +" The above copyright notice and this permission notice +" shall be included in all copies or substantial portions +" of the Software. +" +" THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY +" KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +" THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICU‐ +" LAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +" DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CON‐ +" TRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON‐ +" NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +" THE SOFTWARE. + +" }}} diff --git a/extensions/theme-hybrid/colors/hybrid_dark.json b/extensions/theme-hybrid/colors/hybrid_dark.json new file mode 100644 index 0000000000..48a54c84ee --- /dev/null +++ b/extensions/theme-hybrid/colors/hybrid_dark.json @@ -0,0 +1,46 @@ +{ + "name": "hybrid_dark", + "baseVimTheme": "hybrid", + "baseVimBackground": "dark", + "colors": { + "background": "#1d1f21", + "foreground": "#c5c8c6", + + "title.background": "#1d1f21", + "title.foreground": "#c5c8c6", + + "editor.background": "#1d1f21", + "editor.foreground": "#c5c8c6", + + "tabs.background": "#232c31", + "tabs.foreground": "#c5c8c6", + + "toolTip.background": "#232c31", + "toolTip.foreground": "#c5c8c6", + "toolTip.border": "#242d32", + + "menu.background": "#232c31", + "menu.foreground": "#c5c8c6", + "menu.border": "#242d32", + + "contextMenu.background": "#232c31", + "contextMenu.foreground": "#c5c8c6", + "contextMenu.border": "#242d32", + "contextMenu.highlight": "#373b41", + + "statusBar.background": "#1d1f21", + "statusBar.foreground": "#c5c8c6", + + "highlight.mode.insert.background": "#f0c674", + "highlight.mode.insert.foreground": "#1d1f21", + + "highlight.mode.normal.background": "#81a2be", + "highlight.mode.normal.foreground": "#1d1f21", + + "highlight.mode.operator.background": "#b294bb", + "highlight.mode.operator.foreground": "#1d1f21", + + "highlight.mode.visual.background": "#b5bd68", + "highlight.mode.visual.foreground": "#1d1f21" + } +} diff --git a/extensions/theme-hybrid/colors/hybrid_light.json b/extensions/theme-hybrid/colors/hybrid_light.json new file mode 100644 index 0000000000..56548af8cc --- /dev/null +++ b/extensions/theme-hybrid/colors/hybrid_light.json @@ -0,0 +1,46 @@ +{ + "name": "hybrid_light", + "baseVimTheme": "hybrid", + "baseVimBackground": "light", + "colors": { + "background": "#e4e4e4", + "foreground": "#000000", + + "title.background": "#e4e4e4", + "title.foreground": "#000000", + + "editor.background": "#e4e4e4", + "editor.foreground": "#000000", + + "tabs.background": "#d0d0d0", + "tabs.foreground": "#000000", + + "toolTip.background": "#d0d0d0", + "toolTip.foreground": "#000000", + "toolTip.border": "#bcbcbc", + + "menu.background": "#d0d0d0", + "menu.foreground": "#000000", + "menu.border": "#bcbcbc", + + "contextMenu.background": "#d0d0d0", + "contextMenu.foreground": "#000000", + "contextMenu.border": "#bcbcbc", + "contextMenu.highlight": "#bcbcbc", + + "statusBar.background": "#e4e4e4", + "statusBar.foreground": "#000000", + + "highlight.mode.insert.background": "#5f5f00", + "highlight.mode.insert.foreground": "#e4e4e4", + + "highlight.mode.normal.background": "#00005f", + "highlight.mode.normal.foreground": "#e4e4e4", + + "highlight.mode.operator.background": "#5f005f", + "highlight.mode.operator.foreground": "#e4e4e4", + + "highlight.mode.visual.background": "#005f00", + "highlight.mode.visual.foreground": "#e4e4e4" + } +} diff --git a/extensions/theme-hybrid/package.json b/extensions/theme-hybrid/package.json new file mode 100644 index 0000000000..b8506ea18c --- /dev/null +++ b/extensions/theme-hybrid/package.json @@ -0,0 +1,25 @@ +{ + "name": "onivim-theme-hybrid", + "version": "0.0.1", + "description": "Hybrid theme, ported to Oni", + "engines": { + "oni": "0.3.2" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "contributes": { + "themes": [ + { + "name": "hybrid_dark", + "path": "colors/hybrid_dark.json" + }, + { + "name": "hybrid_light", + "path": "colors/hybrid_light.json" + } + ] + }, + "author": "Parker Ault", + "license": "MIT" +} From 6436fa75e45b287c2a555555cb7fdfa0356b779d Mon Sep 17 00:00:00 2001 From: David Duarte <deltaduartedavid@gmail.com> Date: Tue, 17 Apr 2018 01:16:17 +0200 Subject: [PATCH 34/59] Regression from #2078: Event can be null when Sneak navigation is used (#2099) --- browser/src/Services/Explorer/ExplorerView.tsx | 6 ++++-- browser/src/UI/components/SidebarItemView.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index 2d1ce179f3..4019e0de8f 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -43,8 +43,10 @@ const scrollIntoViewIfNeeded = (elem: HTMLElement) => { elem && elem["scrollIntoViewIfNeeded"] && elem["scrollIntoViewIfNeeded"]() } const stopPropagation = (fn: () => void) => { - return (e: React.MouseEvent<HTMLElement>) => { - e.stopPropagation() + return (e?: React.MouseEvent<HTMLElement>) => { + if (e) { + e.stopPropagation() + } fn() } } diff --git a/browser/src/UI/components/SidebarItemView.tsx b/browser/src/UI/components/SidebarItemView.tsx index 7319e7cee7..ed1009d3f0 100644 --- a/browser/src/UI/components/SidebarItemView.tsx +++ b/browser/src/UI/components/SidebarItemView.tsx @@ -19,7 +19,7 @@ export interface ISidebarItemViewProps { isContainer?: boolean indentationLevel: number icon?: JSX.Element - onClick: (e: React.MouseEvent<HTMLElement>) => void + onClick: (e?: React.MouseEvent<HTMLElement>) => void } const px = (num: number): string => num.toString() + "px" From 2f80093cb17a83257e1058491881334202d99cf0 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Mon, 16 Apr 2018 17:48:32 -0700 Subject: [PATCH 35/59] Fix the version check to properly recognize 0.3.0. (#2103) --- browser/src/neovim/NeovimInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/neovim/NeovimInstance.ts b/browser/src/neovim/NeovimInstance.ts index 69fd9f2164..130d98aa27 100644 --- a/browser/src/neovim/NeovimInstance.ts +++ b/browser/src/neovim/NeovimInstance.ts @@ -1013,7 +1013,7 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { shouldExtTabs: boolean, shouldExtPopups: boolean, ) { - if (major >= 0 && minor >= 2 && patch >= 1) { + if (major > 0 || minor > 2 || (minor === 2 && patch >= 1)) { const useExtCmdLine = this._configuration.getValue("commandline.mode") const useExtWildMenu = this._configuration.getValue("wildmenu.mode") return { From 6ae03e2ab7a16f1ec579702866131990ec3f94e0 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Tue, 17 Apr 2018 17:53:42 -0700 Subject: [PATCH 36/59] Add Channing Conger as a backer - thank you! :) --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index 4f0ae13cf7..c9e45e3733 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -104,6 +104,7 @@ Thanks you to all our backers for making Oni possible! * Ryan Campbell * Balint Fulop * Quasar Jarosz +* Channing Conger <a href="https://opencollective.com/oni/tiers/backer/0/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/0/avatar.png"></a> <a href="https://opencollective.com/oni/tiers/backer/1/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/1/avatar.png"></a> From c29f10c36765a01dfe1d271322d50c1e165ea39e Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Tue, 17 Apr 2018 17:54:25 -0700 Subject: [PATCH 37/59] Add Clinton Bloodworth as a backer - thank you! :) --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index c9e45e3733..b74e97325f 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -105,6 +105,7 @@ Thanks you to all our backers for making Oni possible! * Balint Fulop * Quasar Jarosz * Channing Conger +* Clinton Bloodworth <a href="https://opencollective.com/oni/tiers/backer/0/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/0/avatar.png"></a> <a href="https://opencollective.com/oni/tiers/backer/1/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/1/avatar.png"></a> From 8c3c7d5b3fc935b62f92e6d6522f3864def1beb8 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Tue, 17 Apr 2018 18:11:30 -0700 Subject: [PATCH 38/59] Add Lex Song as a backer - thank you! :) --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index b74e97325f..a7e85cd666 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -106,6 +106,7 @@ Thanks you to all our backers for making Oni possible! * Quasar Jarosz * Channing Conger * Clinton Bloodworth +* Lex Song <a href="https://opencollective.com/oni/tiers/backer/0/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/0/avatar.png"></a> <a href="https://opencollective.com/oni/tiers/backer/1/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/1/avatar.png"></a> From 6ae11349c66d3e18898266d26ef9be4e50dc80dd Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Tue, 17 Apr 2018 18:12:11 -0700 Subject: [PATCH 39/59] Add Paul Baumgart as a backer - thank you! :) --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index a7e85cd666..892f5a5d9d 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -107,6 +107,7 @@ Thanks you to all our backers for making Oni possible! * Channing Conger * Clinton Bloodworth * Lex Song +* Paul Baumgart <a href="https://opencollective.com/oni/tiers/backer/0/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/0/avatar.png"></a> <a href="https://opencollective.com/oni/tiers/backer/1/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/1/avatar.png"></a> From ffacdbba7d1a4a0ee568538ad9011d5183985e32 Mon Sep 17 00:00:00 2001 From: David Duarte <deltaduartedavid@gmail.com> Date: Wed, 18 Apr 2018 04:17:16 +0200 Subject: [PATCH 40/59] Fix relative module loading for configuration (#2106) --- .../Configuration/FileConfigurationProvider.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/browser/src/Services/Configuration/FileConfigurationProvider.ts b/browser/src/Services/Configuration/FileConfigurationProvider.ts index cdef5e8597..d945c175a6 100644 --- a/browser/src/Services/Configuration/FileConfigurationProvider.ts +++ b/browser/src/Services/Configuration/FileConfigurationProvider.ts @@ -125,8 +125,16 @@ export class FileConfigurationProvider implements IConfigurationProvider { let error: Error | null = null if (fs.existsSync(this._configurationFilePath)) { try { - const loadedConfig = global["require"](this._configurationFilePath) // tslint:disable-line no-string-literal - userRuntimeConfig = promoteConfigurationToRootLevel(loadedConfig) + const configurationContent = fs.readFileSync(this._configurationFilePath, "utf-8") + + // Wrap as commonjs module and execute it to use current file path, and so resolve module relativly to current process + const module = { exports: {} } + Function("require", "exports", "module", configurationContent)( + (global as any).require, + module.exports, + module, + ) + userRuntimeConfig = promoteConfigurationToRootLevel(module.exports) } catch (e) { e.message = "[Config Error] Failed to parse " + From 5c616c98a92bc885a31babaeee34654d053ab0e5 Mon Sep 17 00:00:00 2001 From: David Duarte <deltaduartedavid@gmail.com> Date: Wed, 18 Apr 2018 15:39:08 +0200 Subject: [PATCH 41/59] Update to webpack@4 (#2109) --- browser/src/Editor/BufferManager.ts | 10 +- browser/src/Editor/NeovimEditor/markdown.ts | 3 +- browser/webpack.debug.config.js | 11 +- browser/webpack.development.config.js | 2 +- browser/webpack.production.config.js | 12 +- package.json | 16 +- yarn.lock | 3298 +++++++++++++++---- 7 files changed, 2743 insertions(+), 609 deletions(-) diff --git a/browser/src/Editor/BufferManager.ts b/browser/src/Editor/BufferManager.ts index 0e00aa57e2..e12492dfb2 100644 --- a/browser/src/Editor/BufferManager.ts +++ b/browser/src/Editor/BufferManager.ts @@ -15,6 +15,8 @@ import "rxjs/add/operator/concatMap" import { Store } from "redux" +import * as detectIndent from "detect-indent" + import * as Oni from "oni-api" import { @@ -227,13 +229,7 @@ export class Buffer implements IBuffer { } public async detectIndentation(): Promise<BufferIndentationInfo> { - const bufferLinesPromise = this.getLines(0, 1024) - const detectIndentPromise = import("detect-indent") - - const [bufferLines, detectIndent] = await Promise.all([ - bufferLinesPromise, - detectIndentPromise, - ]) + const bufferLines = await this.getLines(0, 1024) const ret = detectIndent(bufferLines.join("\n")) diff --git a/browser/src/Editor/NeovimEditor/markdown.ts b/browser/src/Editor/NeovimEditor/markdown.ts index b6cf7d3ecb..eb41be0de4 100644 --- a/browser/src/Editor/NeovimEditor/markdown.ts +++ b/browser/src/Editor/NeovimEditor/markdown.ts @@ -4,8 +4,7 @@ import * as marked from "marked" import * as Log from "./../../Log" import { IGrammarPerLine, IGrammarToken } from "./../../Services/SyntaxHighlighting/TokenGenerator" -// tslint:disable-next-line -const { default: DOMPurify } = require("dompurify") +import * as DOMPurify from "dompurify" const renderer = new marked.Renderer() interface IRendererArgs { diff --git a/browser/webpack.debug.config.js b/browser/webpack.debug.config.js index 12b7e0166d..7ed8d1a581 100644 --- a/browser/webpack.debug.config.js +++ b/browser/webpack.debug.config.js @@ -6,15 +6,18 @@ const webpack = require("webpack") const baseConfig = require("./webpack.development.config.js") const debugConfig = Object.assign({}, baseConfig, { + devtool: "source-map", plugins: [ new webpack.DefinePlugin({ "process.env.NODE_ENV": '"development"', }), - new webpack.optimize.CommonsChunkPlugin({ - async: true, - minChunks: 2, - }), ], + optimization: { + splitChunks: { + name: "vendor", + minChunks: 2, + }, + }, output: { path: path.join(__dirname, "..", "lib", "browser"), publicPath: "lib/browser/", diff --git a/browser/webpack.development.config.js b/browser/webpack.development.config.js index 61b8b7cc4d..201d4d2c0c 100644 --- a/browser/webpack.development.config.js +++ b/browser/webpack.development.config.js @@ -2,6 +2,7 @@ var path = require("path") var webpack = require("webpack") module.exports = { + mode: "development", entry: [path.join(__dirname, "src/index.tsx")], target: "electron-renderer", externals: { @@ -16,7 +17,6 @@ module.exports = { resolve: { extensions: [".tsx", ".ts", ".js", ".less"], }, - devtool: "cheap-module-eval-source-map", module: { rules: [ { diff --git a/browser/webpack.production.config.js b/browser/webpack.production.config.js index 5a7464482a..e5b1051c10 100644 --- a/browser/webpack.production.config.js +++ b/browser/webpack.production.config.js @@ -5,23 +5,13 @@ const webpack = require("webpack") // Override 'debug' settings const baseConfig = require("./webpack.debug.config.js") -const OptimizeJsPlugin = require("optimize-js-plugin") -const BabiliPlugin = require("babili-webpack-plugin") - const productionConfig = Object.assign({}, baseConfig, { + mode: "production", devtool: false, plugins: [ new webpack.DefinePlugin({ "process.env.NODE_ENV": '"production"', }), - new webpack.optimize.CommonsChunkPlugin({ - async: true, - minChunks: 2, - }), - new BabiliPlugin(), - new OptimizeJsPlugin({ - sourceMap: false, - }), ], }) diff --git a/package.json b/package.json index 069996729b..d2c2c95ec7 100644 --- a/package.json +++ b/package.json @@ -911,8 +911,8 @@ "@types/sinon": "1.16.32", "autoprefixer": "6.4.0", "azure-storage": "^2.8.1", + "babel-minify-webpack-plugin": "^0.3.1", "babel-plugin-dynamic-import-node": "^1.2.0", - "babili-webpack-plugin": "0.1.2", "bs-platform": "2.1.0", "classnames": "2.2.5", "codecov": "^3.0.0", @@ -941,7 +941,7 @@ "jest": "^22.2.2", "jsdom": "11.0.0", "less": "2.7.1", - "less-loader": "4.0.5", + "less-loader": "^4.1.0", "less-plugin-autoprefix": "1.5.1", "lodash": "4.17.0", "lolex": "2.3.1", @@ -952,10 +952,9 @@ "nyc": "^11.4.1", "oni-release-downloader": "^0.0.10", "opencollective": "1.0.3", - "optimize-js-plugin": "0.0.4", "prettier": "^1.10.2", "pretty-quick": "^1.2.2", - "react-hot-loader": "1.3.1", + "react-hot-loader": "^4.0.1", "react-motion": "0.5.2", "react-redux": "5.0.6", "react-test-renderer": "^16.2.0", @@ -973,14 +972,15 @@ "style-loader": "0.18.2", "sudo-prompt": "7.1.1", "ts-jest": "^22.0.4", - "ts-loader": "2.3.2", + "ts-loader": "^4.2.0", "tslint": "5.9.1", "vscode-snippet-parser": "0.0.5", "wcwidth": "1.0.1", "webdriverio": "4.8.0", - "webpack": "3.5.3", - "webpack-bundle-analyzer": "^2.9.1", - "webpack-dev-server": "2.7.1" + "webpack": "^4.6.0", + "webpack-bundle-analyzer": "^2.11.1", + "webpack-cli": "^2.0.14", + "webpack-dev-server": "^3.1.3" }, "collective": { "type": "opencollective", diff --git a/yarn.lock b/yarn.lock index 53ae726d47..f56b42324e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,6 +40,10 @@ esutils "^2.0.2" js-tokens "^3.0.0" +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + "@types/cheerio@*": version "0.22.7" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce" @@ -262,11 +266,18 @@ accepts@~1.3.4: mime-types "~2.1.16" negotiator "0.6.1" -acorn-dynamic-import@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" +accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: - acorn "^4.0.3" + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + dependencies: + acorn "^5.0.0" acorn-globals@^3.1.0: version "3.1.0" @@ -280,15 +291,11 @@ acorn-globals@^4.1.0: dependencies: acorn "^5.0.0" -acorn@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -acorn@^4.0.3, acorn@^4.0.4: +acorn@^4.0.4: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.0.0, acorn@^5.1.1: +acorn@^5.0.0: version "5.2.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" @@ -296,10 +303,6 @@ acorn@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102" -ajv-keywords@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" - ajv-keywords@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" @@ -311,7 +314,7 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5: +ajv@^5.0.0, ajv@^5.1.0: version "5.4.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.4.0.tgz#32d1cf08dbc80c432f426f12e10b2511f6b46474" dependencies: @@ -320,6 +323,15 @@ ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" +ajv@^6.1.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6" + dependencies: + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + uri-js "^3.0.2" + ajv@^6.1.1: version "6.3.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.3.0.tgz#1650a41114ef00574cac10b8032d8f4c14812da7" @@ -356,7 +368,7 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-escapes@^1.1.0: +ansi-escapes@^1.0.0, ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -406,10 +418,18 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" + ansi-wrap@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" +any-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242" + anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" @@ -417,6 +437,13 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + app-builder-bin-linux@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/app-builder-bin-linux/-/app-builder-bin-linux-1.7.2.tgz#a764c8e52ecf1b5b068f32c820c6daf1ffed6a8f" @@ -443,7 +470,7 @@ append-transform@^0.4.0: dependencies: default-require-extensions "^1.0.0" -aproba@^1.0.3: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -519,7 +546,11 @@ arr-diff@^2.0.0: dependencies: arr-flatten "^1.0.1" -arr-flatten@^1.0.1: +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" @@ -527,6 +558,14 @@ arr-union@^2.0.1: version "2.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" @@ -547,6 +586,13 @@ array-flatten@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296" +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + array-map@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" @@ -573,7 +619,11 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" -arrify@^1.0.1: +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -607,6 +657,18 @@ assert@^1.1.1: dependencies: util "0.10.3" +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +ast-types@0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" + +ast-types@0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8" + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -623,11 +685,11 @@ async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" -async@1.x, async@^1.4.0, async@^1.5.2: +async@1.x, async@^1.4.0, async@^1.5.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@2.6.0, async@^2.0.0, async@^2.1.2, async@^2.1.4: +async@2.6.0, async@^2.0.0, async@^2.1.4, async@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" dependencies: @@ -637,6 +699,10 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" +atob@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc" + atob@~1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/atob/-/atob-1.1.3.tgz#95f13629b12c3a51a5d215abdce2aa9f32f80773" @@ -736,33 +802,144 @@ babel-generator@^6.18.0, babel-generator@^6.26.0: source-map "^0.5.6" trim-right "^1.0.1" -babel-helper-evaluate-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.1.0.tgz#95d98c4ea36150483db2e7d3ec9e1954a72629cb" +babel-helper-bindify-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" -babel-helper-flip-expressions@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.1.2.tgz#77f6652f9de9c42401d827bd46ebd2109e3ef18a" +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-evaluate-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.3.0.tgz#2439545e0b6eae5b7f49b790acbebd6b9a73df20" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-flip-expressions@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.3.0.tgz#f5b6394bd5219b43cf8f7b201535ed540c6e7fa2" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" babel-helper-is-nodes-equiv@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684" -babel-helper-is-void-0@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.1.1.tgz#72f21a3abba0bef3837f9174fca731aed9a02888" +babel-helper-is-void-0@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.3.0.tgz#95570d20bd27b2206f68083ae9980ee7003d8fe7" -babel-helper-mark-eval-scopes@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.1.1.tgz#4554345edf9f2549427bd2098e530253f8af2992" +babel-helper-mark-eval-scopes@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.3.0.tgz#b4731314fdd7a89091271a5213b4e12d236e29e8" -babel-helper-remove-or-void@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.1.1.tgz#9d7e1856dc6fafcb41b283a416730dc1844f66d7" +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" -babel-helper-to-multiple-sequence-expressions@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.1.1.tgz#5f1b832b39e4acf954e9137f0251395c71196b35" +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-remove-or-void@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.3.0.tgz#f43c86147c8fcc395a9528cbb31e7ff49d7e16e3" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-to-multiple-sequence-expressions@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.3.0.tgz#8da2275ccc26995566118f7213abfd9af7214427" babel-helpers@^6.24.1: version "6.24.1" @@ -784,6 +961,20 @@ babel-messages@^6.23.0: dependencies: babel-runtime "^6.22.0" +babel-minify-webpack-plugin@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-minify-webpack-plugin/-/babel-minify-webpack-plugin-0.3.1.tgz#292aa240af190e2dcadf4f684d6d84d179b6d5a4" + dependencies: + babel-core "^6.26.0" + babel-preset-minify "^0.3.0" + webpack-sources "^1.0.1" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + babel-plugin-dynamic-import-node@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-1.2.0.tgz#f91631e703e0595e47d4beafbb088576c87fbeee" @@ -802,78 +993,242 @@ babel-plugin-jest-hoist@^22.2.0: version "22.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.2.0.tgz#bd34f39d652406669713b8c89e23ef25c890b993" -babel-plugin-minify-builtins@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.1.3.tgz#4f21a7dcb51f91a04ea71d47ff0e8e3b05fec021" +babel-plugin-minify-builtins@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.3.0.tgz#4740117a6a784063aaf8f092989cf9e4bd484860" dependencies: - babel-helper-evaluate-path "^0.1.0" + babel-helper-evaluate-path "^0.3.0" -babel-plugin-minify-constant-folding@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.1.3.tgz#57bd172adf8b8d74ad7c99612eb950414ebea3ca" +babel-plugin-minify-constant-folding@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.3.0.tgz#687e40336bd4ddd921e0e197f0006235ac184bb9" dependencies: - babel-helper-evaluate-path "^0.1.0" + babel-helper-evaluate-path "^0.3.0" -babel-plugin-minify-dead-code-elimination@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.1.7.tgz#774f536f347b98393a27baa717872968813c342c" +babel-plugin-minify-dead-code-elimination@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.3.0.tgz#a323f686c404b824186ba5583cf7996cac81719e" dependencies: - babel-helper-mark-eval-scopes "^0.1.1" - babel-helper-remove-or-void "^0.1.1" + babel-helper-evaluate-path "^0.3.0" + babel-helper-mark-eval-scopes "^0.3.0" + babel-helper-remove-or-void "^0.3.0" lodash.some "^4.6.0" -babel-plugin-minify-flip-comparisons@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.1.2.tgz#e286b40b7599b18dfea195071e4279465cfc1884" +babel-plugin-minify-flip-comparisons@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.3.0.tgz#6627893a409c9f30ef7f2c89e0c6eea7ee97ddc4" dependencies: - babel-helper-is-void-0 "^0.1.1" + babel-helper-is-void-0 "^0.3.0" -babel-plugin-minify-guarded-expressions@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.1.2.tgz#dfc3d473b0362d9605d3ce0ac1e22328c60d1007" +babel-plugin-minify-guarded-expressions@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.3.0.tgz#2552d96189ef45d9a463f1a6b5e4fa110703ac8d" dependencies: - babel-helper-flip-expressions "^0.1.2" + babel-helper-flip-expressions "^0.3.0" -babel-plugin-minify-infinity@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.1.2.tgz#5f1cf67ddedcba13c8a00da832542df0091a1cd4" +babel-plugin-minify-infinity@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.3.0.tgz#c5ec0edd433517cf31b3af17077c202beb48bbe7" -babel-plugin-minify-mangle-names@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.1.3.tgz#bfa24661a6794fb03833587e55828b65449e06fe" +babel-plugin-minify-mangle-names@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.3.0.tgz#f28561bad0dd2f0380816816bb946e219b3b6135" dependencies: - babel-helper-mark-eval-scopes "^0.1.1" + babel-helper-mark-eval-scopes "^0.3.0" -babel-plugin-minify-numeric-literals@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.1.1.tgz#d4b8b0c925f874714ee33ee4b26678583d7ce7fb" +babel-plugin-minify-numeric-literals@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.3.0.tgz#b57734a612e8a592005407323c321119f27d4b40" -babel-plugin-minify-replace@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.1.2.tgz#b90b9e71ab4d3b36325629a91beabe13b0b16ac1" +babel-plugin-minify-replace@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.3.0.tgz#980125bbf7cbb5a637439de9d0b1b030a4693893" -babel-plugin-minify-simplify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.1.2.tgz#a968f1658fdeb2fc759e81fe331d89829df0f6b9" +babel-plugin-minify-simplify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.3.0.tgz#14574cc74d21c81d3060fafa041010028189f11b" dependencies: - babel-helper-flip-expressions "^0.1.2" + babel-helper-flip-expressions "^0.3.0" babel-helper-is-nodes-equiv "^0.0.1" - babel-helper-to-multiple-sequence-expressions "^0.1.1" + babel-helper-to-multiple-sequence-expressions "^0.3.0" -babel-plugin-minify-type-constructors@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.1.2.tgz#db53c5b76cb8e2fcd45d862f17104c78761337ee" +babel-plugin-minify-type-constructors@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.3.0.tgz#7f5a86ef322c4746364e3c591b8514eeafea6ad4" dependencies: - babel-helper-is-void-0 "^0.1.1" + babel-helper-is-void-0 "^0.3.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" babel-plugin-syntax-dynamic-import@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" -babel-plugin-syntax-object-rest-spread@^6.13.0: +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-class-constructor-call@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" + dependencies: + babel-helper-explode-class "^6.24.1" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" @@ -883,47 +1238,159 @@ babel-plugin-transform-es2015-modules-commonjs@^6.24.1: babel-template "^6.26.0" babel-types "^6.26.0" -babel-plugin-transform-inline-consecutive-adds@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.1.2.tgz#5442e9f1c19c78a7899f8a4dee6fd481f61001f5" +babel-plugin-transform-es2015-modules-systemjs@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" -babel-plugin-transform-member-expression-literals@^6.8.4: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.8.5.tgz#e06ae305cf48d819822e93a70d79269f04d89eec" +babel-plugin-transform-es2015-modules-umd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" -babel-plugin-transform-merge-sibling-variables@^6.8.5: - version "6.8.6" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.8.6.tgz#6d21efa5ee4981f71657fae716f9594bb2622aef" +babel-plugin-transform-es2015-object-super@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" -babel-plugin-transform-minify-booleans@^6.8.2: - version "6.8.3" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.8.3.tgz#5906ed776d3718250519abf1bace44b0b613ddf9" +babel-plugin-transform-export-extensions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.22.0" -babel-plugin-transform-property-literals@^6.8.4: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.5.tgz#67ed5930b34805443452c8b9690c7ebe1e206c40" +babel-plugin-transform-flow-strip-types@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-inline-consecutive-adds@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.3.0.tgz#f07d93689c0002ed2b2b62969bdd99f734e03f57" + +babel-plugin-transform-member-expression-literals@^6.9.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.1.tgz#96be2e9968e7f5497333ae03284ecd5340405489" + +babel-plugin-transform-merge-sibling-variables@^6.9.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.1.tgz#9071e443b21458ce6b0a8d3841ba5a174f5dc282" + +babel-plugin-transform-minify-booleans@^6.9.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.1.tgz#52cba79c00fa509737064055efab22166e140c4d" + +babel-plugin-transform-object-rest-spread@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-property-literals@^6.9.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.1.tgz#6970f93b17793abcde9cf25d2e8cd13e0088e5c9" dependencies: esutils "^2.0.2" -babel-plugin-transform-regexp-constructors@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.1.1.tgz#312ab7487cc88a1c62ee25ea1b6087e89b87799c" +babel-plugin-transform-regenerator@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" -babel-plugin-transform-remove-console@^6.8.4: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.5.tgz#fde9d2d3d725530b0fadd8d31078402410386810" +babel-plugin-transform-regexp-constructors@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.3.0.tgz#9bb2c8dd082271a5cb1b3a441a7c52e8fd07e0f5" -babel-plugin-transform-remove-debugger@^6.8.4: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.8.5.tgz#809584d412bf918f071fdf41e1fdb15ea89cdcd5" +babel-plugin-transform-remove-console@^6.9.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.1.tgz#40fe95d98cae5811d8a0e1889812d78b12859651" -babel-plugin-transform-remove-undefined@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.1.2.tgz#e1ebf51110f6b1e0665f28382ef73f95e5023652" +babel-plugin-transform-remove-debugger@^6.9.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.1.tgz#76552d2e9d6c43d9c676bbfc08f3c2a2cc14be14" + +babel-plugin-transform-remove-undefined@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.3.0.tgz#03f5f0071867781e9beabbc7b77bf8095fd3f3ec" + dependencies: + babel-helper-evaluate-path "^0.3.0" -babel-plugin-transform-simplify-comparison-operators@^6.8.4: - version "6.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.8.5.tgz#a838786baf40cc33a93b95ae09e05591227e43bf" +babel-plugin-transform-simplify-comparison-operators@^6.9.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.1.tgz#5b0d06980a17a780f5318b274c00be2fb1c7c4fe" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" @@ -932,9 +1399,9 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-undefined-to-void@^6.8.2: - version "6.8.3" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.8.3.tgz#fc52707f6ee1ddc71bb91b0d314fbefdeef9beb4" +babel-plugin-transform-undefined-to-void@^6.9.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.1.tgz#d7df9c1dd0ec12e0ffe895ed1445f61f1bf5e221" babel-polyfill@6.23.0: version "6.23.0" @@ -944,33 +1411,34 @@ babel-polyfill@6.23.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-preset-babili@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/babel-preset-babili/-/babel-preset-babili-0.1.4.tgz#ad9d6651002f5bc3f07cab300781167f54724bf2" - dependencies: - babel-plugin-minify-builtins "^0.1.3" - babel-plugin-minify-constant-folding "^0.1.3" - babel-plugin-minify-dead-code-elimination "^0.1.7" - babel-plugin-minify-flip-comparisons "^0.1.2" - babel-plugin-minify-guarded-expressions "^0.1.2" - babel-plugin-minify-infinity "^0.1.2" - babel-plugin-minify-mangle-names "^0.1.3" - babel-plugin-minify-numeric-literals "^0.1.1" - babel-plugin-minify-replace "^0.1.2" - babel-plugin-minify-simplify "^0.1.2" - babel-plugin-minify-type-constructors "^0.1.2" - babel-plugin-transform-inline-consecutive-adds "^0.1.2" - babel-plugin-transform-member-expression-literals "^6.8.4" - babel-plugin-transform-merge-sibling-variables "^6.8.5" - babel-plugin-transform-minify-booleans "^6.8.2" - babel-plugin-transform-property-literals "^6.8.4" - babel-plugin-transform-regexp-constructors "^0.1.1" - babel-plugin-transform-remove-console "^6.8.4" - babel-plugin-transform-remove-debugger "^6.8.4" - babel-plugin-transform-remove-undefined "^0.1.2" - babel-plugin-transform-simplify-comparison-operators "^6.8.4" - babel-plugin-transform-undefined-to-void "^6.8.2" - lodash.isplainobject "^4.0.6" +babel-preset-es2015@^6.9.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.24.1" + babel-plugin-transform-es2015-classes "^6.24.1" + babel-plugin-transform-es2015-computed-properties "^6.24.1" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.24.1" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.24.1" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-plugin-transform-es2015-modules-systemjs "^6.24.1" + babel-plugin-transform-es2015-modules-umd "^6.24.1" + babel-plugin-transform-es2015-object-super "^6.24.1" + babel-plugin-transform-es2015-parameters "^6.24.1" + babel-plugin-transform-es2015-shorthand-properties "^6.24.1" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.24.1" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.24.1" + babel-plugin-transform-regenerator "^6.24.1" babel-preset-jest@^22.0.1, babel-preset-jest@^22.2.0: version "22.2.0" @@ -979,7 +1447,62 @@ babel-preset-jest@^22.0.1, babel-preset-jest@^22.2.0: babel-plugin-jest-hoist "^22.2.0" babel-plugin-syntax-object-rest-spread "^6.13.0" -babel-register@^6.26.0: +babel-preset-minify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.3.0.tgz#7db64afa75f16f6e06c0aa5f25195f6f36784d77" + dependencies: + babel-plugin-minify-builtins "^0.3.0" + babel-plugin-minify-constant-folding "^0.3.0" + babel-plugin-minify-dead-code-elimination "^0.3.0" + babel-plugin-minify-flip-comparisons "^0.3.0" + babel-plugin-minify-guarded-expressions "^0.3.0" + babel-plugin-minify-infinity "^0.3.0" + babel-plugin-minify-mangle-names "^0.3.0" + babel-plugin-minify-numeric-literals "^0.3.0" + babel-plugin-minify-replace "^0.3.0" + babel-plugin-minify-simplify "^0.3.0" + babel-plugin-minify-type-constructors "^0.3.0" + babel-plugin-transform-inline-consecutive-adds "^0.3.0" + babel-plugin-transform-member-expression-literals "^6.9.0" + babel-plugin-transform-merge-sibling-variables "^6.9.0" + babel-plugin-transform-minify-booleans "^6.9.0" + babel-plugin-transform-property-literals "^6.9.0" + babel-plugin-transform-regexp-constructors "^0.3.0" + babel-plugin-transform-remove-console "^6.9.0" + babel-plugin-transform-remove-debugger "^6.9.0" + babel-plugin-transform-remove-undefined "^0.3.0" + babel-plugin-transform-simplify-comparison-operators "^6.9.0" + babel-plugin-transform-undefined-to-void "^6.9.0" + lodash.isplainobject "^4.0.6" + +babel-preset-stage-1@^6.5.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" + dependencies: + babel-plugin-transform-class-constructor-call "^6.24.1" + babel-plugin-transform-export-extensions "^6.22.0" + babel-preset-stage-2 "^6.24.1" + +babel-preset-stage-2@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-decorators "^6.24.1" + babel-preset-stage-3 "^6.24.1" + +babel-preset-stage-3@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.24.1" + babel-plugin-transform-async-to-generator "^6.24.1" + babel-plugin-transform-exponentiation-operator "^6.24.1" + babel-plugin-transform-object-rest-spread "^6.22.0" + +babel-register@^6.26.0, babel-register@^6.9.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: @@ -991,7 +1514,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.2: +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.2: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -1015,7 +1538,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.18.0, babel-traverse@^6.26.0: +babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: @@ -1029,7 +1552,7 @@ babel-traverse@^6.18.0, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.18.0, babel-types@^6.24.1, babel-types@^6.26.0: +babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: @@ -1038,18 +1561,14 @@ babel-types@^6.18.0, babel-types@^6.24.1, babel-types@^6.26.0: lodash "^4.17.4" to-fast-properties "^1.0.3" -babili-webpack-plugin@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babili-webpack-plugin/-/babili-webpack-plugin-0.1.2.tgz#164ac03d5932f6a52143e7ffc06f2711c651b6f2" - dependencies: - babel-core "^6.24.1" - babel-preset-babili "^0.1.4" - webpack-sources "^1.0.1" - -babylon@^6.18.0: +babylon@^6.17.3, babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" +babylon@^7.0.0-beta.30: + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + balanced-match@^0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" @@ -1066,6 +1585,18 @@ base64-js@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" @@ -1074,7 +1605,15 @@ bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: - tweetnacl "^0.14.3" + tweetnacl "^0.14.3" + +bfj-node4@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/bfj-node4/-/bfj-node4-5.3.1.tgz#e23d8b27057f1d0214fc561142ad9db998f26830" + dependencies: + bluebird "^3.5.1" + check-types "^7.3.0" + tryer "^1.0.0" big.js@^3.1.3: version "3.2.0" @@ -1084,6 +1623,10 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" +binaryextensions@2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" + bl@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" @@ -1189,6 +1732,21 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -1276,10 +1834,6 @@ browserslist@~1.3.5: dependencies: caniuse-db "^1.0.30000525" -bs-platform@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-2.1.0.tgz#63560ff8f7142c9c0631559df1c35590b9f6d8b2" - bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -1290,6 +1844,10 @@ buffer-crc32@^0.2.1: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" +buffer-from@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" @@ -1372,6 +1930,50 @@ bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + caching-transform@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-1.0.1.tgz#6dbdb2f20f8d8fbce79f3e94e9d1742dcdf5c0a1" @@ -1467,6 +2069,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chalk@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" @@ -1475,10 +2085,22 @@ chalk@^2.3.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" + dependencies: + ansi-styles "~1.0.0" + has-color "~0.1.0" + strip-ansi "~0.1.0" + chardet@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.0.tgz#0bbe1355ac44d7a3ed4a925707c4ef70f8190f6c" +check-types@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.3.0.tgz#468f571a4435c24248f5fd0cb0e8d87c3c341e7d" + cheerio@^1.0.0-rc.2: version "1.0.0-rc.2" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db" @@ -1490,7 +2112,7 @@ cheerio@^1.0.0-rc.2: lodash "^4.15.0" parse5 "^3.0.1" -chokidar@^1.6.0, chokidar@^1.7.0: +chokidar@^1.6.0: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: @@ -1505,6 +2127,32 @@ chokidar@^1.6.0, chokidar@^1.7.0: optionalDependencies: fsevents "^1.0.0" +chokidar@^2.0.0, chokidar@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.0" + optionalDependencies: + fsevents "^1.1.2" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +chrome-trace-event@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-0.1.3.tgz#d395af2d31c87b90a716c831fe326f69768ec084" + chromium-pickle-js@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" @@ -1526,6 +2174,15 @@ clap@^1.0.9: dependencies: chalk "^1.1.3" +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + 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" @@ -1534,16 +2191,39 @@ cli-boxes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" +cli-cursor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" +cli-spinners@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + cli-spinners@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.1.0.tgz#f1847b168844d917a671eb9d147e3df497c90d06" +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + dependencies: + colors "1.0.3" + +cli-truncate@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" + dependencies: + slice-ansi "0.0.4" + string-width "^1.0.1" + cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -1572,6 +2252,28 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + +clone-response@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + dependencies: + mimic-response "^1.0.0" + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + +clone@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + clone@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" @@ -1580,6 +2282,14 @@ clone@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" +cloneable-readable@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65" + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1602,6 +2312,13 @@ codecov@^3.0.0: request "2.81.0" urlgrey "0.4.4" +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + color-convert@^1.3.0, color-convert@^1.8.2, color-convert@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" @@ -1656,6 +2373,10 @@ colors@0.5.x: version "0.5.1" resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774" +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + colors@^1.1.2, colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -1684,13 +2405,13 @@ commander@^2.11.0: version "2.12.2" resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" -commander@^2.12.1: +commander@^2.12.1, commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" -commander@^2.9.0: - version "2.12.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.1.tgz#468635c4168d06145b9323356d1da84d14ac4a7a" +commander@^2.13.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" commondir@^1.0.1: version "1.0.1" @@ -1700,6 +2421,10 @@ compare-version@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080" +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + compress-commons@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f" @@ -1739,7 +2464,7 @@ concat-stream@1.5.0: readable-stream "~2.0.0" typedarray "~0.0.5" -concat-stream@1.6.0, concat-stream@^1.5.1: +concat-stream@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1747,6 +2472,15 @@ concat-stream@1.6.0, concat-stream@^1.5.1: readable-stream "^2.2.2" typedarray "^0.0.6" +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + concurrently@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.1.0.tgz#dc5ef0459090012604756668894c04b434ef90d1" @@ -1813,6 +2547,21 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -1821,6 +2570,10 @@ core-js@^2.4.0, core-js@^2.5.0: version "2.5.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" +core-js@^2.4.1: + version "2.5.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b" + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -1905,7 +2658,7 @@ cross-spawn@^4, cross-spawn@^4.0.0: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -1913,6 +2666,16 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + cross-unzip@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/cross-unzip/-/cross-unzip-0.0.2.tgz#5183bc47a09559befcf98cc4657964999359372f" @@ -2088,11 +2851,13 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" -d@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + +dargs@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dargs/-/dargs-5.1.0.tgz#ec7ea50c78564cd36c9d5ec18f66329fade27829" dashdash@^1.12.0: version "1.14.1" @@ -2100,10 +2865,18 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +date-fns@^1.27.2: + version "1.29.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" + date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" +dateformat@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" @@ -2118,7 +2891,7 @@ debug@2.2.0: dependencies: ms "0.7.1" -debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.5.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.5.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2134,11 +2907,21 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + dependencies: + mimic-response "^1.0.0" + deep-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" -deep-extend@~0.4.0: +deep-extend@^0.4.0, deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" @@ -2177,6 +2960,25 @@ define-properties@^1.1.2: foreach "^2.0.5" object-keys "^1.0.8" +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -2204,6 +3006,10 @@ depd@1.1.1, depd@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + des.js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" @@ -2215,6 +3021,10 @@ destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" +detect-conflict@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/detect-conflict/-/detect-conflict-1.0.1.tgz#088657a66a961c05019db7c4230883b1c6b4176e" + detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" @@ -2253,6 +3063,10 @@ diff@^3.2.0: version "3.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" +diff@^3.3.1, diff@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + diffie-hellman@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" @@ -2323,6 +3137,10 @@ dom-serializer@0, dom-serializer@~0.1.0: domelementtype "~1.1.1" entities "~1.1.1" +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" @@ -2387,17 +3205,34 @@ duplexer@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" +duplexify@^3.4.2, duplexify@^3.5.3: + version "3.5.4" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.4.tgz#4bb46c1796eabebeec4ca9a2e66b808cb7a3d8b4" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" dependencies: jsbn "~0.1.0" +editions@^1.3.3: + version "1.3.4" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -ejs@^2.5.6, ejs@^2.5.7, ejs@~2.5.6: +ejs@^2.3.1: + version "2.5.8" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.8.tgz#2ab6954619f225e6193b7ac5f7c39c48fefe4380" + +ejs@^2.5.7, ejs@~2.5.6: version "2.5.7" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.7.tgz#cc872c168880ae3c7189762fd5ffc00896c9518a" @@ -2579,6 +3414,10 @@ electron@^1.8.4: electron-download "^3.0.1" extract-zip "^1.0.3" +elegant-spinner@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" + elliptic@^6.0.0: version "6.4.0" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" @@ -2595,9 +3434,9 @@ emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" -encodeurl@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" encoding@^0.1.11: version "0.1.12" @@ -2611,14 +3450,19 @@ end-of-stream@^1.0.0: dependencies: once "^1.4.0" -enhanced-resolve@^3.0.0, enhanced-resolve@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" +end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a" dependencies: graceful-fs "^4.1.2" memory-fs "^0.4.0" - object-assign "^4.0.1" - tapable "^0.2.7" + tapable "^1.0.0" entities@^1.1.1, entities@~1.1.1: version "1.1.1" @@ -2628,6 +3472,10 @@ env-paths@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0" +envinfo@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-4.4.2.tgz#472c49f3a8b9bca73962641ce7cb692bf623cd1c" + enzyme-adapter-react-16@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz#a8f4278b47e082fbca14f5bfb1ee50ee650717b4" @@ -2681,12 +3529,25 @@ errno@^0.1.1, errno@^0.1.3: dependencies: prr "~0.0.0" -error-ex@^1.2.0: +errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" +error@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + dependencies: + string-template "~0.2.1" + xtend "~4.0.0" + es-abstract@^1.5.1, es-abstract@^1.6.1: version "1.10.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" @@ -2697,6 +3558,16 @@ es-abstract@^1.5.1, es-abstract@^1.6.1: is-callable "^1.1.3" is-regex "^1.0.4" +es-abstract@^1.7.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + es-to-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" @@ -2705,62 +3576,10 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.37" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" - dependencies: - es6-iterator "~2.0.1" - es6-symbol "~3.1.1" - -es6-iterator@^2.0.1, es6-iterator@~2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - es6-promise@^4.0.5: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a" -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2791,12 +3610,10 @@ escodegen@^1.6.1, escodegen@^1.9.0: optionalDependencies: source-map "~0.5.6" -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" +eslint-scope@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" esrecurse "^4.1.0" estraverse "^4.1.1" @@ -2808,7 +3625,7 @@ esprima@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" -esprima@^4.0.0: +esprima@^4.0.0, esprima@~4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" @@ -2827,10 +3644,6 @@ estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -estree-walker@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.3.1.tgz#e6b1a51cf7292524e7237c312e5fe6660c1ce1aa" - esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2839,13 +3652,6 @@ etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" - event-kit@^2.0.0: version "2.4.0" resolved "https://registry.yarnpkg.com/event-kit/-/event-kit-2.4.0.tgz#718aaf22df76670024ad66922483e1bba0544f33" @@ -2917,6 +3723,10 @@ execa@^0.8.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -2927,12 +3737,30 @@ expand-brackets@^0.1.4: dependencies: is-posix-bracket "^0.1.0" +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + dependencies: + homedir-polyfill "^1.0.1" + expect@^22.3.0: version "22.3.0" resolved "https://registry.yarnpkg.com/expect/-/expect-22.3.0.tgz#b1cb7db27a951ab6055f43937277152a9f668028" @@ -2944,11 +3772,11 @@ expect@^22.3.0: jest-message-util "^22.2.0" jest-regex-util "^22.1.0" -express@^4.13.3, express@^4.15.2: - version "4.16.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" +express@^4.16.2: + version "4.16.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" dependencies: - accepts "~1.3.4" + accepts "~1.3.5" array-flatten "1.1.1" body-parser "1.18.2" content-disposition "0.5.2" @@ -2956,26 +3784,26 @@ express@^4.13.3, express@^4.15.2: cookie "0.3.1" cookie-signature "1.0.6" debug "2.6.9" - depd "~1.1.1" - encodeurl "~1.0.1" + depd "~1.1.2" + encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.1.0" + finalhandler "1.1.1" fresh "0.5.2" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.2" path-to-regexp "0.1.7" - proxy-addr "~2.0.2" + proxy-addr "~2.0.3" qs "6.5.1" range-parser "~1.2.0" safe-buffer "5.1.1" - send "0.16.1" - serve-static "1.13.1" + send "0.16.2" + serve-static "1.13.2" setprototypeof "1.1.0" - statuses "~1.3.1" - type-is "~1.6.15" + statuses "~1.4.0" + type-is "~1.6.16" utils-merge "1.0.1" vary "~1.1.2" @@ -2985,6 +3813,19 @@ extend-shallow@^1.1.2: dependencies: kind-of "^1.1.0" +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + extend@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/extend/-/extend-1.2.1.tgz#a0f5fd6cfc83a5fe49ef698d60ec8a624dd4576c" @@ -3001,12 +3842,33 @@ external-editor@^2.0.1, external-editor@^2.0.4: iconv-lite "^0.4.17" tmp "^0.0.33" +external-editor@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + extract-zip@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.0.tgz#7f400c9607ea866ecab7aa6d54fb978eeb11621a" @@ -3037,7 +3899,7 @@ fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" -fast-levenshtein@~2.0.4: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -3085,6 +3947,13 @@ fd-slicer@~1.0.1: dependencies: pend "~1.2.0" +figures@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -3102,9 +3971,9 @@ fileset@^2.0.2: glob "^7.0.3" minimatch "^3.0.3" -filesize@^3.5.9: - version "3.5.11" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.11.tgz#1919326749433bb3cf77368bd158caabcc19e9ee" +filesize@^3.5.11: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" fill-range@^2.1.0: version "2.2.3" @@ -3116,16 +3985,25 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" dependencies: debug "2.6.9" - encodeurl "~1.0.1" + encodeurl "~1.0.2" escape-html "~1.0.3" on-finished "~2.3.0" parseurl "~1.3.2" - statuses "~1.3.1" + statuses "~1.4.0" unpipe "~1.0.0" find-cache-dir@^0.1.1: @@ -3136,6 +4014,14 @@ find-cache-dir@^0.1.1: mkdirp "^0.5.1" pkg-dir "^1.0.0" +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + find-index@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" @@ -3161,11 +4047,28 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" +first-chunk-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70" + dependencies: + readable-stream "^2.0.2" + flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -for-in@^1.0.1: +flow-parser@^0.*: + version "0.70.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.70.0.tgz#9c310187efe4380ba9a251284e9b83b95c49e857" + +flush-write-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -3216,10 +4119,23 @@ forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" +from2@^2.1.0, from2@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + fs-extra-p@^4.5.0, fs-extra-p@^4.5.2: version "4.5.2" resolved "https://registry.yarnpkg.com/fs-extra-p/-/fs-extra-p-4.5.2.tgz#0a22aba489284d17f375d5dc5139aa777fe2df51" @@ -3273,14 +4189,23 @@ fs-extra@^5.0.0: resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" dependencies: graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.0.0, fsevents@^1.1.1: +fsevents@^1.0.0, fsevents@^1.1.1, fsevents@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" dependencies: @@ -3347,6 +4272,10 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" +get-stream@3.0.0, get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + get-stream@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" @@ -3354,9 +4283,9 @@ get-stream@^2.2.0: object-assign "^4.0.1" pinkie-promise "^2.0.0" -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" getpass@^0.1.1: version "0.1.7" @@ -3364,6 +4293,13 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +gh-got@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0" + dependencies: + got "^7.0.0" + is-plain-obj "^1.1.0" + github-releases@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/github-releases/-/github-releases-0.4.1.tgz#4a13bdf85c4161344271db3d81db08e7379102ff" @@ -3373,6 +4309,19 @@ github-releases@^0.4.1: prettyjson "1.2.1" request "2.81.0" +github-username@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417" + dependencies: + gh-got "^6.0.0" + +glob-all@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.1.0.tgz#8913ddfb5ee1ac7812656241b03d5217c64b02ab" + dependencies: + glob "^7.0.5" + yargs "~1.2.6" + glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -3386,6 +4335,13 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + glob2base@^0.0.12: version "0.0.12" resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" @@ -3430,6 +4386,31 @@ global-dirs@^0.1.0: dependencies: ini "^1.3.4" +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -3468,6 +4449,47 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" +got@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +got@^8.2.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/got/-/got-8.3.0.tgz#6ba26e75f8a6cc4c6b3eb1fe7ce4fec7abac8533" + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.4.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -3476,6 +4498,12 @@ graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" +grouped-queue@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c" + dependencies: + lodash "^4.17.2" + growl@1.10.3: version "1.10.3" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" @@ -3488,11 +4516,12 @@ growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" -gzip-size@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520" +gzip-size@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-4.1.0.tgz#8ae096257eabe7d69c45be2b67c448124ffb517c" dependencies: duplexer "^0.1.1" + pify "^3.0.0" handle-thing@^1.2.5: version "1.2.5" @@ -3542,6 +4571,10 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" +has-color@~0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" @@ -3554,14 +4587,51 @@ has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + dependencies: + has-symbol-support-x "^1.4.1" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + has@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" @@ -3634,6 +4704,10 @@ hoist-non-react-statics@^2.1.0, hoist-non-react-statics@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" +hoist-non-react-statics@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -3645,6 +4719,12 @@ home-path@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/home-path/-/home-path-1.0.5.tgz#788b29815b12d53bacf575648476e6f9041d133f" +homedir-polyfill@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + hosted-git-info@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" @@ -3687,6 +4767,10 @@ htmlparser2@^3.9.1: inherits "^2.0.1" readable-stream "^2.0.2" +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" @@ -3704,14 +4788,14 @@ http-parser-js@>=0.4.0: version "0.4.9" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.9.tgz#ea1a04fb64adff0242e9974f297dd4c3cad271e1" -http-proxy-middleware@~0.17.4: - version "0.17.4" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833" +http-proxy-middleware@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" dependencies: http-proxy "^1.16.2" - is-glob "^3.1.0" - lodash "^4.17.2" - micromatch "^2.3.11" + is-glob "^4.0.0" + lodash "^4.17.5" + micromatch "^3.1.9" http-proxy@^1.16.2: version "1.16.2" @@ -3766,6 +4850,10 @@ ieee754@^1.1.4, ieee754@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + ignore@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" @@ -3795,6 +4883,10 @@ indent-string@^2.1.0: dependencies: repeating "^2.0.0" +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" @@ -3844,7 +4936,7 @@ inquirer@3.0.6, inquirer@~3.0.6: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@~3.3.0: +inquirer@^3.3.0, inquirer@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: @@ -3863,11 +4955,29 @@ inquirer@~3.3.0: strip-ansi "^4.0.0" through "^2.3.6" +inquirer@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.1.0" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^5.5.2" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + int64-buffer@^0.1.9: version "0.1.9" resolved "https://registry.yarnpkg.com/int64-buffer/-/int64-buffer-0.1.9.tgz#9e039da043b24f78b196b283e04653ef5e990f61" -internal-ip@^1.2.0: +internal-ip@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" dependencies: @@ -3877,6 +4987,17 @@ interpret@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" +interpret@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" + +into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + invariant@^2.0.0, invariant@^2.1.0, invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" @@ -3891,14 +5012,26 @@ ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" -ipaddr.js@1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0" +ipaddr.js@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" is-absolute-url@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -3943,10 +5076,38 @@ is-ci@^1.1.0: dependencies: ci-info "^1.0.0" +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" @@ -3961,15 +5122,21 @@ is-equal-shallow@^0.1.3: dependencies: is-primitive "^2.0.0" -is-extendable@^0.1.1: +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" -is-extglob@^2.1.0: +is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -4009,6 +5176,12 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + is-installed-globally@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" @@ -4036,10 +5209,30 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + +is-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-0.2.0.tgz#b361311d83c6e5d726cabf5e250b0237106f5ae2" + dependencies: + symbol-observable "^0.2.2" + +is-odd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + dependencies: + is-number "^4.0.0" + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -4056,11 +5249,11 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.0.1" -is-plain-obj@^1.0.0: +is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" -is-plain-object@^2.0.1: +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" dependencies: @@ -4088,10 +5281,16 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" -is-retry-allowed@^1.0.0: +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" +is-scoped@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-1.0.0.tgz#449ca98299e713038256289ecb2b540dc437cb30" + dependencies: + scoped-regex "^1.0.0" + is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -4122,6 +5321,14 @@ is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -4144,7 +5351,7 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isobject@^3.0.1: +isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" @@ -4298,6 +5505,21 @@ istanbul@0.4.5: which "^1.1.1" wordwrap "^1.0.0" +istextorbinary@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.2.1.tgz#a5231a08ef6dd22b268d0895084cf8d58b5bec53" + dependencies: + binaryextensions "2" + editions "^1.3.3" + textextensions "2" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + jest-changed-files@^22.2.0: version "22.2.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-22.2.0.tgz#517610c4a8ca0925bdc88b0ca53bd678aa8d019e" @@ -4582,6 +5804,46 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" +jscodeshift@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.4.1.tgz#da91a1c2eccfa03a3387a21d39948e251ced444a" + dependencies: + async "^1.5.0" + babel-plugin-transform-flow-strip-types "^6.8.0" + babel-preset-es2015 "^6.9.0" + babel-preset-stage-1 "^6.5.0" + babel-register "^6.9.0" + babylon "^6.17.3" + colors "^1.1.2" + flow-parser "^0.*" + lodash "^4.13.1" + micromatch "^2.3.7" + node-dir "0.1.8" + nomnom "^1.8.1" + recast "^0.12.5" + temp "^0.8.1" + write-file-atomic "^1.2.0" + +jscodeshift@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.5.0.tgz#bdb7b6cc20dd62c16aa728c3fa2d2fe66ca7c748" + dependencies: + babel-plugin-transform-flow-strip-types "^6.8.0" + babel-preset-es2015 "^6.9.0" + babel-preset-stage-1 "^6.5.0" + babel-register "^6.9.0" + babylon "^7.0.0-beta.30" + colors "^1.1.2" + flow-parser "^0.*" + lodash "^4.13.1" + micromatch "^2.3.7" + neo-async "^2.5.0" + node-dir "0.1.8" + nomnom "^1.8.1" + recast "^0.14.1" + temp "^0.8.1" + write-file-atomic "^1.2.0" + jsdom@11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.0.0.tgz#1ee507cb2c0b16c875002476b1a8557d951353e5" @@ -4647,15 +5909,19 @@ jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + json-edm-parser@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/json-edm-parser/-/json-edm-parser-0.1.2.tgz#1e60b0fef1bc0af67bc0d146dfdde5486cd615b4" dependencies: jsonparse "~1.2.0" -json-loader@^0.5.4: - version "0.5.7" - resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" json-schema-traverse@^0.3.0: version "0.3.1" @@ -4725,11 +5991,21 @@ keyboard-layout@2.0.13: event-kit "^2.0.0" nan "^2.0.0" +keyv@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + dependencies: + json-buffer "3.0.0" + +killable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b" + kind-of@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" -kind-of@^3.0.2: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: @@ -4741,6 +6017,14 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + klaw@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" @@ -4777,13 +6061,13 @@ left-pad@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee" -less-loader@4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.0.5.tgz#ae155a7406cac6acd293d785587fcff0f478c4dd" +less-loader@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.1.0.tgz#2c1352c5b09a4f84101490274fd51674de41363e" dependencies: clone "^2.1.1" loader-utils "^1.1.0" - pify "^2.3.0" + pify "^3.0.0" less-plugin-autoprefix@1.5.1: version "1.5.1" @@ -4815,6 +6099,54 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +listr-silent-renderer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" + +listr-update-renderer@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7" + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + elegant-spinner "^1.0.1" + figures "^1.7.0" + indent-string "^3.0.0" + log-symbols "^1.0.2" + log-update "^1.0.2" + strip-ansi "^3.0.1" + +listr-verbose-renderer@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35" + dependencies: + chalk "^1.1.3" + cli-cursor "^1.0.2" + date-fns "^1.27.2" + figures "^1.7.0" + +listr@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/listr/-/listr-0.13.0.tgz#20bb0ba30bae660ee84cc0503df4be3d5623887d" + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + figures "^1.7.0" + indent-string "^2.1.0" + is-observable "^0.2.0" + is-promise "^2.1.0" + is-stream "^1.1.0" + listr-silent-renderer "^1.1.1" + listr-update-renderer "^0.4.0" + listr-verbose-renderer "^0.4.0" + log-symbols "^1.0.2" + log-update "^1.0.2" + ora "^0.2.3" + p-map "^1.1.1" + rxjs "^5.4.2" + stream-to-observable "^0.2.0" + strip-ansi "^3.0.1" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -4825,13 +6157,13 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" dependencies: graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" + parse-json "^4.0.0" + pify "^3.0.0" strip-bom "^3.0.0" loader-runner@^2.3.0: @@ -4880,7 +6212,7 @@ lodash._isiterateecall@^3.0.0: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" -lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0: +lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" @@ -4940,7 +6272,7 @@ lodash@4.17.0: version "4.17.0" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.0.tgz#93f4466e5ab73e5a1f1216c34eea11535f0a8df5" -lodash@4.17.5, lodash@^4.15.0: +lodash@4.17.5, lodash@^4.15.0, lodash@^4.17.5: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" @@ -4954,10 +6286,27 @@ log-symbols@^1.0.2: dependencies: chalk "^1.0.0" +log-symbols@^2.1.0, log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +log-update@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1" + dependencies: + ansi-escapes "^1.0.0" + cli-cursor "^1.0.2" + loglevel@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.0.tgz#ae0caa561111498c5ba13723d6fb631d24003934" +loglevelnext@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.4.tgz#0d991d9998180991dac8bd81e73a596a8720a645" + lokijs@1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.2.tgz#75d43df21232f1d5479d191a69b6ebf61754a873" @@ -4980,14 +6329,14 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.0, loose-envify@^1.3 dependencies: js-tokens "^3.0.0" -loud-rejection@^1.0.0: +loud-rejection@^1.0.0, loud-rejection@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" -lowercase-keys@^1.0.0: +lowercase-keys@1.0.0, lowercase-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" @@ -4998,32 +6347,49 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + macaddress@^0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" -magic-string@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.16.0.tgz#970ebb0da7193301285fb1aa650f39bdd81eb45a" - dependencies: - vlq "^0.2.1" - make-dir@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51" dependencies: pify "^3.0.0" +make-dir@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" + dependencies: + pify "^3.0.0" + makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" dependencies: tmpl "1.0.x" +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + marked@^0.3.6: version "0.3.7" resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.7.tgz#80ef3bbf1bd00d1c9cfebe42ba1b8c85da258d0d" @@ -5053,6 +6419,29 @@ media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" +mem-fs-editor@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz#dd0a6eaf2bb8a6b37740067aa549eb530105af9f" + dependencies: + commondir "^1.0.1" + deep-extend "^0.4.0" + ejs "^2.3.1" + glob "^7.0.3" + globby "^6.1.0" + mkdirp "^0.5.0" + multimatch "^2.0.0" + rimraf "^2.2.8" + through2 "^2.0.0" + vinyl "^2.0.1" + +mem-fs@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc" + dependencies: + through2 "^2.0.0" + vinyl "^1.1.0" + vinyl-file "^2.0.0" + mem@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" @@ -5105,7 +6494,7 @@ methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^2.1.5, micromatch@^2.3.11: +micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: @@ -5123,6 +6512,24 @@ micromatch@^2.1.5, micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" +micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -5138,20 +6545,34 @@ mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: mime-db "~1.30.0" +mime-types@~2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" -mime@^1.2.11, mime@^1.4.1: +mime@^1.2.11: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" +mime@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" + mime@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/mime/-/mime-2.2.0.tgz#161e541965551d3b549fa1114391e3a3d55b923b" @@ -5160,6 +6581,16 @@ mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" +mimic-response@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -5182,10 +6613,36 @@ minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2 version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +minimist@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" + minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + mkdirp@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" @@ -5233,6 +6690,17 @@ moment@^2.11.2: version "2.19.2" resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.2.tgz#8a7f774c95a64550b4c7ebd496683908f9419dbe" +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + mri@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.0.tgz#5c0a3f29c8ccffbbb1ec941dcec09d71fa32f36a" @@ -5265,6 +6733,15 @@ multicast-dns@^6.0.1: dns-packet "^1.0.1" thunky "^0.1.0" +multimatch@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" + dependencies: + array-differ "^1.0.0" + array-union "^1.0.1" + arrify "^1.0.0" + minimatch "^3.0.0" + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -5273,6 +6750,23 @@ nan@^2.0.0, nan@^2.0.9, nan@^2.3.0: version "2.8.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" +nanomatch@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-odd "^2.0.0" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -5290,12 +6784,24 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" +neo-async@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee" + +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + node-abi@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.2.tgz#4da6caceb6685fcd31e7dd1994ef6bb7d0a9c0b2" dependencies: semver "^5.4.1" +node-dir@0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" + node-fetch@1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" @@ -5389,6 +6895,13 @@ node-pre-gyp@^0.6.39: tar "^2.2.1" tar-pack "^3.4.0" +nomnom@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" + dependencies: + chalk "~0.4.0" + underscore "~1.6.0" + nomnom@~1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.6.2.tgz#84a66a260174408fc5b77a18f888eccc44fb6971" @@ -5422,7 +6935,7 @@ normalize-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" -normalize-path@^2.0.0, normalize-path@^2.0.1: +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: @@ -5432,6 +6945,14 @@ normalize-range@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" +normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + normalize-url@^1.4.0: version "1.9.1" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" @@ -5530,6 +7051,14 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + object-inspect@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.5.0.tgz#9d876c11e40f485c79215670281b767488f9bfe3" @@ -5546,6 +7075,12 @@ object-keys@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + object.assign@^4.0.4, object.assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" @@ -5578,6 +7113,12 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + object.values@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a" @@ -5617,21 +7158,25 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@1.x, once@^1.3.0, once@^1.3.3, once@^1.4.0: +once@1.x, once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" +onetime@^1.0.0: + version "1.1.0" + resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" dependencies: mimic-fn "^1.0.0" -oni-api@^0.0.41: - version "0.0.41" - resolved "https://registry.yarnpkg.com/oni-api/-/oni-api-0.0.41.tgz#42bb55d27d63f173fb378da2e1f70a0ad753e4f5" +oni-api@^0.0.42: + version "0.0.42" + resolved "https://registry.yarnpkg.com/oni-api/-/oni-api-0.0.42.tgz#79cab4289809bda1c7b86590119f0c7aaa5a053e" oni-neovim-binaries@0.1.1: version "0.1.1" @@ -5683,6 +7228,12 @@ opn@4.0.2: object-assign "^4.0.1" pinkie-promise "^2.0.0" +opn@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + dependencies: + is-wsl "^1.1.0" + optimist@0.6.1, optimist@^0.6.1, optimist@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -5690,23 +7241,6 @@ optimist@0.6.1, optimist@^0.6.1, optimist@~0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optimize-js-plugin@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/optimize-js-plugin/-/optimize-js-plugin-0.0.4.tgz#69e7a67e0f66c69f7fc0c7b25c5d33b2db6c2817" - dependencies: - optimize-js "^1.0.0" - webpack-sources "^0.1.2" - -optimize-js@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/optimize-js/-/optimize-js-1.0.3.tgz#4326af8657c4a5ff32daf726631754f72ab7fdbc" - dependencies: - acorn "^3.3.0" - concat-stream "^1.5.1" - estree-walker "^0.3.0" - magic-string "^0.16.0" - yargs "^4.8.1" - optionator@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -5718,6 +7252,15 @@ optionator@^0.8.1: type-check "~0.3.2" wordwrap "~1.0.0" +ora@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + dependencies: + chalk "^1.1.1" + cli-cursor "^1.0.2" + cli-spinners "^0.1.2" + object-assign "^4.0.1" + ora@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ora/-/ora-1.3.0.tgz#80078dd2b92a934af66a3ad72a5b910694ede51a" @@ -5766,10 +7309,32 @@ osenv@0, osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + +p-cancelable@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + +p-each-series@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" + dependencies: + p-reduce "^1.0.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + +p-lazy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-lazy/-/p-lazy-1.0.0.tgz#ec53c802f2ee3ac28f166cc82d0b2b02de27a835" + p-limit@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" @@ -5784,6 +7349,22 @@ p-map@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + dependencies: + p-finally "^1.0.0" + +p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + dependencies: + p-finally "^1.0.0" + package-json@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" @@ -5797,6 +7378,14 @@ pako@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + parse-asn1@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" @@ -5828,6 +7417,17 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -5842,10 +7442,18 @@ parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + path-exists@^2.0.0, path-exists@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -5864,7 +7472,7 @@ path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" -path-key@^2.0.0: +path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -5884,11 +7492,11 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" dependencies: - pify "^2.0.0" + pify "^3.0.0" pbkdf2@^3.0.3: version "3.0.14" @@ -5980,6 +7588,10 @@ portfinder@^1.0.9: debug "^2.2.0" mkdirp "0.5.x" +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + postcss-calc@^5.2.0: version "5.3.1" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" @@ -6234,6 +7846,10 @@ prepend-http@^1.0.0, prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" @@ -6242,6 +7858,10 @@ prettier@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.10.2.tgz#1af8356d1842276a99a5b5529c82dd9e9ad3cc93" +prettier@^1.5.3: + version "1.12.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" + pretty-bytes@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" @@ -6249,6 +7869,10 @@ pretty-bytes@^1.0.2: get-stdin "^4.0.1" meow "^3.1.0" +pretty-bytes@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9" + pretty-format@^22.1.0: version "22.1.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.1.0.tgz#2277605b40ed4529ae4db51ff62f4be817647914" @@ -6273,10 +7897,14 @@ prettyjson@1.2.1: colors "^1.1.2" minimist "^1.2.0" -private@^0.1.7: +private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" @@ -6285,6 +7913,10 @@ process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + progress-stream@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" @@ -6292,6 +7924,10 @@ progress-stream@^1.1.0: speedometer "~0.1.2" through2 "~0.2.3" +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -6306,17 +7942,29 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0: loose-envify "^1.3.1" object-assign "^4.1.1" -proxy-addr@~2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" +prop-types@^15.6.1: + version "15.6.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.3.1" + object-assign "^4.1.1" + +proxy-addr@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" dependencies: forwarded "~0.1.2" - ipaddr.js "1.5.2" + ipaddr.js "1.6.0" prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -6331,6 +7979,21 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.4.0.tgz#80b7c5df7e24153d03f0e7ac8a05a5d068bd07fb" + dependencies: + duplexify "^3.5.3" + inherits "^2.0.3" + pump "^2.0.0" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -6362,6 +8025,14 @@ query-string@^4.1.0: object-assign "^4.1.0" strict-uri-encode "^1.0.0" +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -6463,16 +8134,15 @@ react-dom@16.0.0: object-assign "^4.1.1" prop-types "^15.6.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" - -react-hot-loader@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-1.3.1.tgz#c95647ae78b73dfceff6ec71ffcb04182ff6daf9" +react-hot-loader@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.0.1.tgz#48284350ae5d7ba07dac872bd5bbc6e477352593" dependencies: - react-hot-api "^0.4.5" - source-map "^0.4.4" + fast-levenshtein "^2.0.6" + global "^4.3.0" + hoist-non-react-statics "^2.5.0" + prop-types "^15.6.1" + shallowequal "^1.0.2" react-motion@0.5.2: version "0.5.2" @@ -6540,6 +8210,13 @@ react@16.0.0: object-assign "^4.1.1" prop-types "^15.6.0" +read-chunk@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655" + dependencies: + pify "^3.0.0" + safe-buffer "^5.1.1" + read-config-file@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-config-file/-/read-config-file-3.0.0.tgz#771def5184a7f76abaf6b2c82f20cb983775b8ea" @@ -6561,12 +8238,12 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" dependencies: find-up "^2.0.0" - read-pkg "^2.0.0" + read-pkg "^3.0.0" read-pkg@^1.0.0: version "1.1.0" @@ -6576,13 +8253,25 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" dependencies: - load-json-file "^2.0.0" + load-json-file "^4.0.0" normalize-package-data "^2.3.2" - path-type "^2.0.0" + path-type "^3.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.4, readable-stream@^2.1.5, readable-stream@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6, readable-stream@^2.2.9, readable-stream@^2.3.3: version "2.3.3" @@ -6631,6 +8320,25 @@ realpath-native@^1.0.0: dependencies: util.promisify "^1.0.0" +recast@^0.12.5: + version "0.12.9" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1" + dependencies: + ast-types "0.10.1" + core-js "^2.4.1" + esprima "~4.0.0" + private "~0.1.5" + source-map "~0.6.1" + +recast@^0.14.1: + version "0.14.7" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d" + dependencies: + ast-types "0.11.3" + esprima "~4.0.0" + private "~0.1.5" + source-map "~0.6.1" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -6697,12 +8405,27 @@ regenerator-runtime@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" dependencies: is-equal-shallow "^0.1.3" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + regexpu-core@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" @@ -6711,6 +8434,14 @@ regexpu-core@^1.0.0: regjsgen "^0.2.0" regjsparser "^0.1.4" +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + registry-auth-token@^3.0.1: version "3.3.1" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.1.tgz#fb0d3289ee0d9ada2cbb52af5dfe66cb070d3006" @@ -6753,7 +8484,7 @@ repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" -repeat-string@^1.5.2: +repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" @@ -6763,6 +8494,14 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + request-promise-core@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" @@ -6880,6 +8619,13 @@ resolve-cwd@^2.0.0: dependencies: resolve-from "^3.0.0" +resolve-dir@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" @@ -6888,7 +8634,7 @@ resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" -resolve-url@~0.2.1: +resolve-url@^0.2.1, resolve-url@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -6902,6 +8648,19 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: dependencies: path-parse "^1.0.5" +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -6929,6 +8688,10 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2. dependencies: glob "^7.0.5" +rimraf@~2.2.6: + version "2.2.8" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" @@ -6943,12 +8706,18 @@ rst-selector-parser@^2.2.3: lodash.flattendeep "^4.4.0" nearley "^2.7.10" -run-async@^2.2.0: +run-async@^2.0.0, run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + rx-lite-aggregates@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" @@ -6973,6 +8742,12 @@ rxjs@^5.1.1: dependencies: symbol-observable "^1.0.1" +rxjs@^5.4.2, rxjs@^5.5.2: + version "5.5.10" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.10.tgz#fde02d7a614f6c8683d0d1957827f492e09db045" + dependencies: + symbol-observable "1.0.1" + rxjs@^5.5.8: version "5.5.8" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.8.tgz#b2b0809a57614ad6254c03d7446dea0d83ca3791" @@ -6987,6 +8762,12 @@ safe-buffer@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + samsam@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567" @@ -7029,6 +8810,17 @@ schema-utils@^0.3.0: dependencies: ajv "^5.0.0" +schema-utils@^0.4.4, schema-utils@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +scoped-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8" + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -7057,14 +8849,14 @@ semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" -send@0.16.1: - version "0.16.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" dependencies: debug "2.6.9" - depd "~1.1.1" + depd "~1.1.2" destroy "~1.0.4" - encodeurl "~1.0.1" + encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" @@ -7073,7 +8865,11 @@ send@0.16.1: ms "2.0.0" on-finished "~2.3.0" range-parser "~1.2.0" - statuses "~1.3.1" + statuses "~1.4.0" + +serialize-javascript@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" serve-index@^1.7.2: version "1.9.1" @@ -7087,14 +8883,14 @@ serve-index@^1.7.2: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719" +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" dependencies: - encodeurl "~1.0.1" + encodeurl "~1.0.2" escape-html "~1.0.3" parseurl "~1.3.2" - send "0.16.1" + send "0.16.2" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" @@ -7104,6 +8900,24 @@ set-immediate-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -7123,6 +8937,10 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shallowequal@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.0.2.tgz#1561dbdefb8c01408100319085764da3fcf83f8f" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -7158,6 +8976,14 @@ shelljs@0.7.7: interpret "^1.0.0" rechoir "^0.6.2" +shelljs@^0.8.0: + version "0.8.1" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.1.tgz#729e038c413a2254c4078b95ed46e0397154a9f1" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" @@ -7191,10 +9017,41 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + sntp@1.x.x: version "1.0.9" resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" @@ -7218,12 +9075,12 @@ sockjs-client@1.1.4: json3 "^3.3.2" url-parse "^1.1.8" -sockjs@0.3.18: - version "0.3.18" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.18.tgz#d9b289316ca7df77595ef299e075f0f937eb4207" +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" dependencies: faye-websocket "^0.10.0" - uuid "^2.0.2" + uuid "^3.0.1" sort-keys@^1.0.0: version "1.1.2" @@ -7231,7 +9088,13 @@ sort-keys@^1.0.0: dependencies: is-plain-obj "^1.0.0" -source-list-map@^0.1.7, source-list-map@~0.1.7: +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" @@ -7248,6 +9111,16 @@ source-map-resolve@^0.3.0: source-map-url "~0.3.0" urix "~0.1.0" +source-map-resolve@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + dependencies: + atob "^2.0.0" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" @@ -7266,6 +9139,10 @@ source-map-support@^0.5.3, source-map-support@^0.5.4: dependencies: source-map "^0.6.0" +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + source-map-url@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" @@ -7282,7 +9159,7 @@ source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6: +source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -7370,6 +9247,12 @@ speedometer@~0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + split@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" @@ -7394,6 +9277,12 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + dependencies: + safe-buffer "^5.1.1" + stack-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" @@ -7402,13 +9291,16 @@ stat-mode@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.2.2.tgz#e6c80b623123d7d80cf132ce538f346289072502" -"statuses@>= 1.3.1 < 2": - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" -statuses@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" +"statuses@>= 1.3.1 < 2", statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" stealthy-require@^1.1.0: version "1.1.1" @@ -7421,6 +9313,13 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" +stream-each@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + stream-http@^2.7.2: version "2.7.2" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad" @@ -7431,6 +9330,16 @@ stream-http@^2.7.2: to-arraybuffer "^1.0.0" xtend "^4.0.0" +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +stream-to-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.2.0.tgz#59d6ea393d87c2c0ddac10aa0d561bc6ba6f0e10" + dependencies: + any-observable "^0.2.0" + strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" @@ -7442,6 +9351,10 @@ string-length@^2.0.0: astral-regex "^1.0.0" strip-ansi "^4.0.0" +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -7467,6 +9380,12 @@ string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -7489,6 +9408,17 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" + +strip-bom-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca" + dependencies: + first-chunk-stream "^2.0.0" + strip-bom "^2.0.0" + strip-bom@3.0.0, strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -7585,18 +9515,24 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.1.2, supports-color@^3.2.3, supports-color@~3.2.3: +supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3, supports-color@~3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" dependencies: has-flag "^1.0.0" -supports-color@^4.0.0, supports-color@^4.2.1, supports-color@^4.4.0: +supports-color@^4.0.0, supports-color@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" dependencies: has-flag "^2.0.0" +supports-color@^5.1.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + supports-color@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" @@ -7625,6 +9561,10 @@ symbol-observable@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" +symbol-observable@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-0.2.4.tgz#95a83db26186d6af7e7a18dbd9760a2f86d08f40" + symbol-observable@^1.0.1, symbol-observable@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" @@ -7633,9 +9573,9 @@ symbol-tree@^3.2.1, symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" -tapable@^0.2.7: - version "0.2.8" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" +tapable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" tar-pack@^3.4.0: version "3.4.1" @@ -7676,6 +9616,13 @@ temp-file@^3.1.1: fs-extra-p "^4.5.0" lazy-val "^1.0.3" +temp@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + dependencies: + os-tmpdir "^1.0.0" + rimraf "~2.2.6" + term-size@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" @@ -7692,6 +9639,14 @@ test-exclude@^4.1.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +textextensions@2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" + throat@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" @@ -7707,6 +9662,13 @@ through2@2.0.1: readable-stream "~2.0.0" xtend "~4.0.0" +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + through2@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" @@ -7722,11 +9684,7 @@ thunky@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e" -time-stamp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357" - -timed-out@^4.0.0: +timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -7754,6 +9712,28 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + tough-cookie@>=2.3.3, tough-cookie@^2.3.2, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" @@ -7788,6 +9768,10 @@ truncate-utf8-bytes@^1.0.0: dependencies: utf8-byte-length "^1.0.1" +tryer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.0.tgz#027b69fa823225e551cace3ef03b11f6ab37c1d7" + ts-jest@^22.0.4: version "22.0.4" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-22.0.4.tgz#be5e8d7d2cf3f3ef97d877a6a0562508c3f64515" @@ -7803,13 +9787,14 @@ ts-jest@^22.0.4: source-map-support "^0.5.0" yargs "^11.0.0" -ts-loader@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-2.3.2.tgz#b71b9f0d0062c791a654d462140718f9f7817665" +ts-loader@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-4.2.0.tgz#c380c399fc81f82cad0e3044f9c1f775ecde6efa" dependencies: - chalk "^2.0.1" - enhanced-resolve "^3.0.0" + chalk "^2.3.0" + enhanced-resolve "^4.0.0" loader-utils "^1.0.2" + micromatch "^3.1.4" semver "^5.0.1" tslib@^1.8.0, tslib@^1.8.1: @@ -7866,6 +9851,13 @@ type-is@~1.6.15: media-typer "0.3.0" mime-types "~2.1.15" +type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -7878,7 +9870,14 @@ ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" -uglify-js@^2.6, uglify-js@^2.8.29: +uglify-es@^3.3.4: + version "3.3.9" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + +uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: @@ -7891,13 +9890,18 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" -uglifyjs-webpack-plugin@^0.4.6: - version "0.4.6" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" +uglifyjs-webpack-plugin@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.4.tgz#5eec941b2e9b8538be0a20fc6eda25b14c7c1043" dependencies: - source-map "^0.5.6" - uglify-js "^2.8.29" - webpack-sources "^1.0.1" + cacache "^10.0.4" + find-cache-dir "^1.0.0" + schema-utils "^0.4.5" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" uid-number@^0.0.6: version "0.0.6" @@ -7911,10 +9915,23 @@ underscore@~1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604" +underscore@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" + underscore@~1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -7929,6 +9946,18 @@ uniqs@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" +unique-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + unique-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" @@ -7943,10 +9972,25 @@ unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +untildify@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" + unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" +upath@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" + update-notifier@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.3.0.tgz#4e8827a6bb915140ab093559d7014e3ebb837451" @@ -7961,16 +10005,32 @@ update-notifier@^2.3.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" +uri-js@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-3.0.2.tgz#f90b858507f81dea4dcfbb3c4c3dbfa2b557faaa" + dependencies: + punycode "^2.1.0" + urix@^0.1.0, urix@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" +url-join@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a" + url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" dependencies: prepend-http "^1.0.1" +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + dependencies: + prepend-http "^2.0.0" + url-parse@1.0.x: version "1.0.5" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" @@ -7985,6 +10045,10 @@ url-parse@^1.1.8: querystringify "~1.0.0" requires-port "~1.0.0" +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + url@^0.11.0, url@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -7996,6 +10060,12 @@ urlgrey@0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f" +use@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" + dependencies: + kind-of "^6.0.2" + utf8-byte-length@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" @@ -8021,14 +10091,18 @@ utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" -uuid@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - uuid@^3.0.0, uuid@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" +uuid@^3.0.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + +v8-compile-cache@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" + validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" @@ -8060,9 +10134,35 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vlq@^0.2.1: - version "0.2.3" - resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" +vinyl-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a" + dependencies: + graceful-fs "^4.1.2" + pify "^2.3.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + strip-bom-stream "^2.0.0" + vinyl "^1.1.0" + +vinyl@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" vm-browserify@0.0.4: version "0.0.4" @@ -8178,13 +10278,13 @@ watch@~0.18.0: exec-sh "^0.2.0" minimist "^1.2.0" -watchpack@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac" +watchpack@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.5.0.tgz#231e783af830a22f8966f65c4c4bacc814072eed" dependencies: - async "^2.1.2" - chokidar "^1.7.0" + chokidar "^2.0.2" graceful-fs "^4.1.2" + neo-async "^2.5.0" wbuf@^1.1.0, wbuf@^1.7.2: version "1.7.2" @@ -8263,66 +10363,113 @@ webidl-conversions@^4.0.0, webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" -webpack-bundle-analyzer@^2.9.1: - version "2.9.1" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.9.1.tgz#c2c8e03e8e5768ed288b39ae9e27a8b8d7b9d476" +webpack-addons@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/webpack-addons/-/webpack-addons-1.1.5.tgz#2b178dfe873fb6e75e40a819fa5c26e4a9bc837a" dependencies: - acorn "^5.1.1" - chalk "^1.1.3" - commander "^2.9.0" - ejs "^2.5.6" - express "^4.15.2" - filesize "^3.5.9" - gzip-size "^3.0.0" + jscodeshift "^0.4.0" + +webpack-bundle-analyzer@^2.11.1: + version "2.11.1" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.11.1.tgz#b9fbfb6a32c0a8c1c3237223e90890796b950ab9" + dependencies: + acorn "^5.3.0" + bfj-node4 "^5.2.0" + chalk "^2.3.0" + commander "^2.13.0" + ejs "^2.5.7" + express "^4.16.2" + filesize "^3.5.11" + gzip-size "^4.1.0" lodash "^4.17.4" mkdirp "^0.5.1" opener "^1.4.3" - ws "^3.3.1" + ws "^4.0.0" -webpack-dev-middleware@^1.11.0: - version "1.12.1" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.1.tgz#338be3ca930973be1c2ce07d84d275e997e1a25a" +webpack-cli@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-2.0.14.tgz#71d03d8c10547c1dfd674f71ff3b0457c33a74cd" + dependencies: + chalk "^2.3.2" + cross-spawn "^6.0.5" + diff "^3.5.0" + enhanced-resolve "^4.0.0" + envinfo "^4.4.2" + glob-all "^3.1.0" + global-modules "^1.0.0" + got "^8.2.0" + import-local "^1.0.0" + inquirer "^5.1.0" + interpret "^1.0.4" + jscodeshift "^0.5.0" + listr "^0.13.0" + loader-utils "^1.1.0" + lodash "^4.17.5" + log-symbols "^2.2.0" + mkdirp "^0.5.1" + p-each-series "^1.0.0" + p-lazy "^1.0.0" + prettier "^1.5.3" + supports-color "^5.3.0" + v8-compile-cache "^1.1.2" + webpack-addons "^1.1.5" + yargs "^11.1.0" + yeoman-environment "^2.0.0" + yeoman-generator "^2.0.3" + +webpack-dev-middleware@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.1.2.tgz#be4d0c36a4fa7d69d6904093418514caa9df3a40" dependencies: + loud-rejection "^1.6.0" memory-fs "~0.4.1" - mime "^1.4.1" + mime "^2.1.0" path-is-absolute "^1.0.0" range-parser "^1.0.3" - time-stamp "^2.0.0" + url-join "^4.0.0" + webpack-log "^1.0.1" -webpack-dev-server@2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.7.1.tgz#21580f5a08cd065c71144cf6f61c345bca59a8b8" +webpack-dev-server@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.3.tgz#5cecfd8a9d60c4638284813f1cf9562f04e5c1c5" dependencies: ansi-html "0.0.7" + array-includes "^3.0.3" bonjour "^3.5.0" - chokidar "^1.6.0" + chokidar "^2.0.0" compression "^1.5.2" connect-history-api-fallback "^1.3.0" + debug "^3.1.0" del "^3.0.0" - express "^4.13.3" + express "^4.16.2" html-entities "^1.2.0" - http-proxy-middleware "~0.17.4" - internal-ip "^1.2.0" + http-proxy-middleware "~0.18.0" + import-local "^1.0.0" + internal-ip "1.2.0" ip "^1.1.5" + killable "^1.0.0" loglevel "^1.4.1" - opn "4.0.2" + opn "^5.1.0" portfinder "^1.0.9" selfsigned "^1.9.1" serve-index "^1.7.2" - sockjs "0.3.18" + sockjs "0.3.19" sockjs-client "1.1.4" spdy "^3.4.1" strip-ansi "^3.0.0" - supports-color "^3.1.1" - webpack-dev-middleware "^1.11.0" - yargs "^6.0.0" + supports-color "^5.1.0" + webpack-dev-middleware "3.1.2" + webpack-log "^1.1.2" + yargs "11.0.0" -webpack-sources@^0.1.2: - version "0.1.5" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.5.tgz#aa1f3abf0f0d74db7111c40e500b84f966640750" +webpack-log@^1.0.1, webpack-log@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d" dependencies: - source-list-map "~0.1.7" - source-map "~0.5.3" + chalk "^2.1.0" + log-symbols "^2.1.0" + loglevelnext "^1.0.1" + uuid "^3.1.0" webpack-sources@^1.0.1: version "1.0.2" @@ -8331,32 +10478,36 @@ webpack-sources@^1.0.1: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.5.3.tgz#e68653963bda146e212832c04a4d8041d2b4b8c8" +webpack-sources@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.6.0.tgz#363eafa733710eb0ed28c512b2b9b9f5fb01e69b" dependencies: acorn "^5.0.0" - acorn-dynamic-import "^2.0.0" - ajv "^5.1.5" - ajv-keywords "^2.0.0" - async "^2.1.2" - enhanced-resolve "^3.4.0" - escope "^3.6.0" - interpret "^1.0.0" - json-loader "^0.5.4" - json5 "^0.5.1" + acorn-dynamic-import "^3.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^0.1.1" + enhanced-resolve "^4.0.0" + eslint-scope "^3.7.1" loader-runner "^2.3.0" loader-utils "^1.1.0" memory-fs "~0.4.1" + micromatch "^3.1.8" mkdirp "~0.5.0" + neo-async "^2.5.0" node-libs-browser "^2.0.0" - source-map "^0.5.3" - supports-color "^4.2.1" - tapable "^0.2.7" - uglifyjs-webpack-plugin "^0.4.6" - watchpack "^1.4.0" + schema-utils "^0.4.4" + tapable "^1.0.0" + uglifyjs-webpack-plugin "^1.2.4" + watchpack "^1.5.0" webpack-sources "^1.0.1" - yargs "^8.0.2" websocket-driver@>=0.5.1: version "0.7.0" @@ -8410,7 +10561,7 @@ which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@1, which@^1.1.1, which@^1.2.12, which@^1.2.9, which@^1.3.0: +which@1, which@^1.1.1, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" dependencies: @@ -8432,10 +10583,6 @@ window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -8448,6 +10595,12 @@ wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + dependencies: + errno "~0.1.7" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -8459,7 +10612,7 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -write-file-atomic@^1.1.4: +write-file-atomic@^1.1.4, write-file-atomic@^1.2.0: version "1.3.4" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" dependencies: @@ -8475,14 +10628,6 @@ write-file-atomic@^2.0.0, write-file-atomic@^2.1.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" -ws@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.2.tgz#96c1d08b3fefda1d5c1e33700d3bfaa9be2d5608" - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - ws@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/ws/-/ws-4.0.0.tgz#bfe1da4c08eeb9780b986e0e4d10eccd7345999f" @@ -8521,7 +10666,7 @@ xmldom@0.1.x: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" -xtend@^4.0.0, xtend@~4.0.0: +xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -8535,35 +10680,20 @@ y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" -yargs-parser@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.0.6" - -yargs-parser@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" - dependencies: - camelcase "^3.0.0" - yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" dependencies: camelcase "^3.0.0" -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - dependencies: - camelcase "^4.1.0" - yargs-parser@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.0.0.tgz#21d476330e5a82279a4b881345bf066102e219c6" @@ -8576,24 +10706,7 @@ yargs-parser@^9.0.2: dependencies: camelcase "^4.1.0" -yargs@^10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.0.3.tgz#6542debd9080ad517ec5048fb454efe9e4d4aaae" - dependencies: - cliui "^3.2.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^8.0.0" - -yargs@^11.0.0: +yargs@11.0.0, yargs@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b" dependencies: @@ -8610,42 +10723,39 @@ yargs@^11.0.0: y18n "^3.2.1" yargs-parser "^9.0.2" -yargs@^4.8.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" +yargs@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.0.3.tgz#6542debd9080ad517ec5048fb454efe9e4d4aaae" dependencies: cliui "^3.2.0" decamelize "^1.1.1" + find-up "^2.1.0" get-caller-file "^1.0.1" - lodash.assign "^4.0.3" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" + os-locale "^2.0.0" require-directory "^2.1.1" require-main-filename "^1.0.1" set-blocking "^2.0.0" - string-width "^1.0.1" - which-module "^1.0.0" - window-size "^0.2.0" + string-width "^2.0.0" + which-module "^2.0.0" y18n "^3.2.1" - yargs-parser "^2.4.1" + yargs-parser "^8.0.0" -yargs@^6.0.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" +yargs@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" dependencies: - camelcase "^3.0.0" - cliui "^3.2.0" + cliui "^4.0.0" decamelize "^1.1.1" + find-up "^2.1.0" get-caller-file "^1.0.1" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" + os-locale "^2.0.0" require-directory "^2.1.1" require-main-filename "^1.0.1" set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" + string-width "^2.0.0" + which-module "^2.0.0" y18n "^3.2.1" - yargs-parser "^4.2.0" + yargs-parser "^9.0.2" yargs@^7.0.2: version "7.1.0" @@ -8665,23 +10775,11 @@ yargs@^7.0.2: y18n "^3.2.1" yargs-parser "^5.0.0" -yargs@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" +yargs@~1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b" dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" + minimist "^0.1.0" yargs@~3.10.0: version "3.10.0" @@ -8698,6 +10796,54 @@ yauzl@2.4.1: dependencies: fd-slicer "~1.0.1" +yeoman-environment@^2.0.0, yeoman-environment@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.6.tgz#ae1b21d826b363f3d637f88a7fc9ea7414cb5377" + dependencies: + chalk "^2.1.0" + debug "^3.1.0" + diff "^3.3.1" + escape-string-regexp "^1.0.2" + globby "^6.1.0" + grouped-queue "^0.3.3" + inquirer "^3.3.0" + is-scoped "^1.0.0" + lodash "^4.17.4" + log-symbols "^2.1.0" + mem-fs "^1.1.0" + text-table "^0.2.0" + untildify "^3.0.2" + +yeoman-generator@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-2.0.4.tgz#c1c51580ab88506233dd6e837a4bbf8a8e34c9a6" + dependencies: + async "^2.6.0" + chalk "^2.3.0" + cli-table "^0.3.1" + cross-spawn "^5.1.0" + dargs "^5.1.0" + dateformat "^3.0.2" + debug "^3.1.0" + detect-conflict "^1.0.0" + error "^7.0.2" + find-up "^2.1.0" + github-username "^4.0.0" + istextorbinary "^2.1.0" + lodash "^4.17.4" + make-dir "^1.1.0" + mem-fs-editor "^3.0.2" + minimist "^1.2.0" + pretty-bytes "^4.0.2" + read-chunk "^2.1.0" + read-pkg-up "^3.0.0" + rimraf "^2.6.2" + run-async "^2.0.0" + shelljs "^0.8.0" + text-table "^0.2.0" + through2 "^2.0.0" + yeoman-environment "^2.0.5" + zip-stream@^1.1.0, zip-stream@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04" From 073c39542f174459f8787e37accd0860b1d384db Mon Sep 17 00:00:00 2001 From: David Duarte <deltaduartedavid@gmail.com> Date: Wed, 18 Apr 2018 20:36:53 +0200 Subject: [PATCH 42/59] Give baseUrl to ts compiler to use relative path in oni ts configuration (#2107) --- .../src/TypeScriptConfigurationEditor.ts | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/vim/core/oni-plugin-typescript/src/TypeScriptConfigurationEditor.ts b/vim/core/oni-plugin-typescript/src/TypeScriptConfigurationEditor.ts index 6411cc194c..0f9d5b5972 100644 --- a/vim/core/oni-plugin-typescript/src/TypeScriptConfigurationEditor.ts +++ b/vim/core/oni-plugin-typescript/src/TypeScriptConfigurationEditor.ts @@ -9,9 +9,9 @@ import * as path from "path" const normalizePath = (str: string) => str.split("\\").join("\\\\") -const tsConfigTemplate = (typePath: string) => ` -import * as React from "${normalizePath(path.join(typePath, "react"))}" -import * as Oni from "${normalizePath(path.join(typePath, "oni-api"))}" +const tsConfigTemplate = ` +import * as React from "react" +import * as Oni from "oni-api" export const activate = (oni: Oni.Plugin.Api) => { console.log("config activated") @@ -58,7 +58,24 @@ const getTypeScriptConfigurationFromJavaScriptConfiguration = (configurationFile const ensureTsConfig = async (typeScriptConfigFile: string, typeRoots: string): Promise<void> => { if (!fs.existsSync(typeScriptConfigFile)) { - fs.writeFileSync(typeScriptConfigFile, tsConfigTemplate(typeRoots)) + fs.writeFileSync(typeScriptConfigFile, tsConfigTemplate) + } + // Add a tsconfig.json file to provide completion on config + const tsConfig = path.join(path.dirname(typeScriptConfigFile), "tsconfig.json") + if (!fs.existsSync(tsConfig)) { + fs.writeFileSync( + tsConfig, + JSON.stringify( + { + compilerOptions: { + jsx: "react", + baseUrl: typeRoots, + }, + }, + null, + 2, + ), + ) } } @@ -91,12 +108,14 @@ export class TypeScriptConfigurationEditor { public async transpileConfigurationToJavaScript(contents: string): Promise<string> { const ts = await import("typescript") + const typeRoots = path.join(this._mainProcessDirectory, "node_modules") const output = ts.transpileModule(contents, { reportDiagnostics: true, compilerOptions: { - jsx: "React", - } as any, + jsx: ts.JsxEmit.React, + baseUrl: typeRoots, + }, }) return output.outputText From ee134d3e0519b78daad94fc9c93d0fdcbf3dca73 Mon Sep 17 00:00:00 2001 From: David Duarte <deltaduartedavid@gmail.com> Date: Thu, 19 Apr 2018 03:58:37 +0200 Subject: [PATCH 43/59] Use Vim shell option as default value for terminal.shellCommand (#2098) --- .../Services/Configuration/DefaultConfiguration.ts | 2 +- browser/src/Services/Terminal.ts | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 3d3a1f03c7..79f109959f 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -410,7 +410,7 @@ const BaseConfiguration: IConfigurationValues = { "tabs.showIndex": false, "tabs.wrap": false, - "terminal.shellCommand": os.platform() === "win32" ? "cmd" : "bash", + "terminal.shellCommand": null, "ui.animations.enabled": true, "ui.colorscheme": "nord", diff --git a/browser/src/Services/Terminal.ts b/browser/src/Services/Terminal.ts index 7120816fe9..18c744e3e0 100644 --- a/browser/src/Services/Terminal.ts +++ b/browser/src/Services/Terminal.ts @@ -15,13 +15,12 @@ export const activate = ( configuration: Configuration, editorManager: EditorManager, ) => { - const getTerminalCommand = () => { - const terminalCommand = configuration.getValue("terminal.shellCommand", "") - return `term://${terminalCommand}` - } + const openTerminal = async (openMode: Oni.FileOpenMode) => { + const terminalCommand = + configuration.getValue("terminal.shellCommand") || + (await editorManager.activeEditor.neovim.callFunction("nvim_get_option", ["shell"])) - const openTerminal = (openMode: Oni.FileOpenMode) => { - editorManager.activeEditor.openFile(getTerminalCommand(), { openMode }) + editorManager.activeEditor.openFile(`term://${terminalCommand}`, { openMode }) } commandManager.registerCommand({ From b96c4cfe2ff7bbe5c97a11fd4b1e869dbe5f5c5f Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Thu, 19 Apr 2018 05:59:23 +0100 Subject: [PATCH 44/59] Feature/add file/folder manipulation commands to explorer (#1839) * add yank and paste functionality [WIP] * add yank paste commands and reducer to the store * add initial working yank and paste command functionality * allow yanks to be stored as array for multiselecting * add timeout to remove yanked items after a minute idle add leave handler to reset yank and paste register allow toggle functionality if item already yanked * add h and l to expand and collapse dirs * add initial undo register and hopeless transitions * [WIP] add initial working..not fully tested undo functionality * move logic out of split into epics - for undo funcitionality also add guards if none present and remove an undo if successful from the register * add is focused to sidebar type * expose is focused method and check for it before applying bindings * add initial tests for yank epic * add epic test [wip] * remove types for memory fs since it needs to be required? * remove unsused vars * remove paste folder in test * add delete undo functionality add new methods to filesystem to have it control the shell commands * fix lint error * fix config typing typo * add true delete command and associated function rename methods of filesystem * fix broken utility function * add tests for Explorer file system * fix failing test * add coverage output directory * update tests - add move collection add is ci utility * commit utility file * fix changed typing to moveNodes function * add tests for small utilities * rename persist file function * switch to use of path.join in moving * finalise animation and tidy up epics * add reducer tests, use lodash utilities not homegrown * fix tests [WIP] fix epic typing for delete * fix notification message * fix delete epic and map to refresh * inject promisify as well as fs into oni file system * fix type errors * inject promisify and [wip] mock in jest test * refactor move logic out of split into filesystem add epic for pasting * fix undo functionality * refactor some method names for readablility * consolidate actions for typing and reuse * delegate error handling to epic catch clauses for greater flexibility as this gives back access to the observable so potentially a retry could be attempted or map to another action etc. * refactor notifications into epics fix jest test * add error notification with reason * consolidate replicated code into a function * set failures to warning level * fix tests.ts and ad log to paste * add get source node method to use to ensure undo causes expansion * move jest test to unit tests dir :sad: * add passing paste epic test * rename explorer filestystem tests * move fs-extra to deps add moar tests * add undo epic tests * add test for deletion in undo epic * remove redundant function and replace with fs-extra fn * add clear update functionality to prevent re-animating * add test for clear update epics * gate bindings not to apply if commandline or menu are open * fix paste action error handling * fix tests by ensuring mocks are async * import specific helpers from rxjs not all of observable fix tests simplify updating * set jest to collect coverage from components dir only --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 1 + browser/src/Input/KeyBindings.ts | 24 + browser/src/Plugins/PluginInstaller.ts | 5 +- .../Configuration/DefaultConfiguration.ts | 3 + .../Configuration/IConfigurationValues.ts | 6 + .../Services/Explorer/ExplorerFileSystem.ts | 107 +++ .../Services/Explorer/ExplorerSelectors.ts | 9 + .../src/Services/Explorer/ExplorerSplit.tsx | 223 ++++--- .../src/Services/Explorer/ExplorerStore.ts | 613 ++++++++++++++++-- .../src/Services/Explorer/ExplorerView.tsx | 144 ++-- browser/src/Services/Sidebar/SidebarStore.ts | 4 + browser/src/UI/components/SidebarItemView.tsx | 25 +- browser/src/Utility.ts | 12 - browser/src/neovim/NeovimInstance.ts | 5 +- .../Explorer/ExplorerFileSystemTests.ts | 77 +++ .../Services/Explorer/ExplorerStoreTests.ts | 362 ++++++++++- jest.config.js | 4 +- package.json | 381 ++++------- ui-tests/tsconfig.react.json | 2 +- yarn.lock | 41 +- 20 files changed, 1531 insertions(+), 517 deletions(-) create mode 100644 browser/test/Services/Explorer/ExplorerFileSystemTests.ts diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 06e63124cf..7b90d56824 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -745,6 +745,7 @@ export class NeovimEditor extends Editor implements IEditor { document.body.ondrop = ev => { ev.preventDefault() + // TODO: the following line currently breaks explorer drag and drop functionality ev.stopPropagation() const { files } = ev.dataTransfer diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index e0316ed56d..93efe00ae3 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -9,6 +9,13 @@ import * as Oni from "oni-api" import * as Platform from "./../Platform" import { Configuration } from "./../Services/Configuration" +interface ISidebar { + sidebar: { + activeEntryId: string + isFocused: boolean + } +} + export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configuration): void => { const { editors, input, menu } = oni @@ -20,6 +27,13 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati const isInsertOrCommandMode = () => editors.activeEditor.mode === "insert" || editors.activeEditor.mode === "cmdline_normal" + const oniWithSidebar = oni as Oni.Plugin.Api & ISidebar + const isExplorerActive = () => + oniWithSidebar.sidebar.activeEntryId === "oni.sidebar.explorer" && + oniWithSidebar.sidebar.isFocused && + !isInsertOrCommandMode() && + !isMenuOpen() + const isMenuOpen = () => menu.isMenuOpen() if (Platform.isMac()) { @@ -119,6 +133,16 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind("<s-c-b>", "sidebar.toggle", isNormalMode) + // Explorer + input.bind("d", "explorer.delete.persist", isExplorerActive) + input.bind("<c-d>", "explorer.delete", isExplorerActive) + input.bind("y", "explorer.yank", isExplorerActive) + input.bind("p", "explorer.paste", isExplorerActive) + input.bind("u", "explorer.undo", isExplorerActive) + input.bind("h", "explorer.collapse.directory", isExplorerActive) + input.bind("l", "explorer.expand.directory", isExplorerActive) + + // Browser input.bind("k", "browser.scrollUp") input.bind("j", "browser.scrollDown") input.bind("h", "browser.scrollLeft") diff --git a/browser/src/Plugins/PluginInstaller.ts b/browser/src/Plugins/PluginInstaller.ts index 3f6983a93f..d88aa1d7eb 100644 --- a/browser/src/Plugins/PluginInstaller.ts +++ b/browser/src/Plugins/PluginInstaller.ts @@ -4,7 +4,6 @@ * Responsible for installing, updating, and uninstalling plugins. */ -import * as fs from "fs" import * as path from "path" import { Event, IEvent } from "oni-types" @@ -17,7 +16,7 @@ import { getUserConfigFolderPath } from "./../Services/Configuration" // import { AnonymousPlugin } from "./AnonymousPlugin" // import { Plugin } from "./Plugin" -import { FileSystem, IFileSystem } from "./../Services/Explorer/ExplorerFileSystem" +import { IFileSystem, OniFileSystem } from "./../Services/Explorer/ExplorerFileSystem" import Process from "./Api/Process" @@ -62,7 +61,7 @@ export class YarnPluginInstaller implements IPluginInstaller { return this._onOperationError } - constructor(private _fileSystem: IFileSystem = new FileSystem(fs)) {} + constructor(private _fileSystem: IFileSystem = OniFileSystem) {} public async install(identifier: string): Promise<void> { const eventInfo: IPluginInstallerOperationEvent = { diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 79f109959f..9899433c62 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -128,6 +128,9 @@ const BaseConfiguration: IConfigurationValues = { "editor.imageLayerExtensions": [".gif", ".jpg", ".jpeg", ".bmp", ".png"], + "explorer.persistDeletedFiles": true, + "explorer.maxUndoFileSizeInBytes": 500_000, + "environment.additionalPaths": [], "keyDisplayer.showInInsertMode": false, diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index adb2f58815..5f9ec8f431 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -189,6 +189,12 @@ export interface IConfigurationValues { // 'zero-latency' mode typing, and increases responsiveness. "editor.typingPrediction": boolean + // Files deleted in the explorer can be persisted for the duration + // of the session meaning that deletion can be undone is this is set + // to true + "explorer.persistDeletedFiles": boolean + "explorer.maxUndoFileSizeInBytes": number + "editor.fullScreenOnStart": boolean "editor.maximizeScreenOnStart": boolean diff --git a/browser/src/Services/Explorer/ExplorerFileSystem.ts b/browser/src/Services/Explorer/ExplorerFileSystem.ts index 82d6379495..f8dc5cd74f 100644 --- a/browser/src/Services/Explorer/ExplorerFileSystem.ts +++ b/browser/src/Services/Explorer/ExplorerFileSystem.ts @@ -5,9 +5,12 @@ */ import * as fs from "fs" +import { emptyDirSync, ensureDirSync, move, remove } from "fs-extra" +import * as os from "os" import * as path from "path" import { promisify } from "util" +import { ExplorerNode } from "./ExplorerSelectors" import { FolderOrFile } from "./ExplorerStore" /** @@ -16,6 +19,12 @@ import { FolderOrFile } from "./ExplorerStore" export interface IFileSystem { readdir(fullPath: string): Promise<FolderOrFile[]> exists(fullPath: string): Promise<boolean> + persistNode(fullPath: string): Promise<void> + restoreNode(fullPath: string): Promise<void> + deleteNode(node: ExplorerNode): Promise<void> + canPersistNode(fullPath: string, size: number): Promise<boolean> + move(source: string, dest: string): Promise<void> + moveNodesBack(collection: Array<{ source: string; destination: string }>): Promise<void> } export class FileSystem implements IFileSystem { @@ -25,12 +34,25 @@ export class FileSystem implements IFileSystem { exists(path: string): Promise<boolean> } + private _backupDirectory = path.join(os.tmpdir(), "oni_backup") + + public get backupDir(): string { + return this._backupDirectory + } + constructor(nfs: typeof fs) { this._fs = { readdir: promisify(nfs.readdir.bind(nfs)), stat: promisify(nfs.stat.bind(nfs)), exists: promisify(nfs.exists.bind(nfs)), } + + this.init() + } + + public init = () => { + ensureDirSync(this._backupDirectory) + emptyDirSync(this._backupDirectory) } public async readdir(directoryPath: string): Promise<FolderOrFile[]> { @@ -58,4 +80,89 @@ export class FileSystem implements IFileSystem { public exists(fullPath: string): Promise<boolean> { return this._fs.exists(fullPath) } + + /** + * Delete a file or Folder + * + * @name deleteNode + * @function + * @param {ExplorerNode} node The file or folder node + */ + public deleteNode = async (node: ExplorerNode): Promise<void> => { + switch (node.type) { + case "folder": + await remove(node.folderPath) + break + case "file": + await remove(node.filePath) + break + default: + break + } + } + + /** + * Move a file or folder from the backup dir to its original location + * + * @name restoreNode + * @function + * @param {string} fileOrFolder The file or folder path + */ + public restoreNode = async (prevPath: string): Promise<void> => { + const name = path.basename(prevPath) + const backupPath = path.join(this._backupDirectory, name) + await move(backupPath, prevPath) + } + + public move = async (source: string, dest: string): Promise<void> => { + return this.areDifferent(source, dest) && move(source, dest) + } + /** + * Saves a file to the tmp directory to persist deleted files + * + * @name PersistNode + * @function + * @param {string} filename A file or folder path + */ + public persistNode = async (fileOrFolder: string): Promise<void> => { + const { size } = await this._fs.stat(fileOrFolder) + const hasEnoughSpace = os.freemem() > size + if (hasEnoughSpace) { + const filename = path.basename(fileOrFolder) + const newPath = path.join(this._backupDirectory, filename) + await move(fileOrFolder, newPath, { overwrite: true }) + } + } + + /** + * Moves an array of files and folders to their original locations + * + * @name moveNodesBack + * @function + * @param {Array} collection An array of object with a file/folder and its destination folder + * @returns {void} + */ + public moveNodesBack = async ( + collection: Array<{ destination: string; source: string }>, + ): Promise<void> => { + await Promise.all( + collection.map( + async ({ source, destination }) => + this.areDifferent(source, destination) && move(destination, source), + ), + ) + } + + /** + * canPersistNode + * Determine based on size whether the directory should be persisted + */ + public canPersistNode = async (fullPath: string, maxSize: number): Promise<boolean> => { + const { size } = await this._fs.stat(fullPath) + return size < maxSize + } + + private areDifferent = (src: string, dest: string) => src !== dest } + +export const OniFileSystem = new FileSystem(fs) diff --git a/browser/src/Services/Explorer/ExplorerSelectors.ts b/browser/src/Services/Explorer/ExplorerSelectors.ts index a770ab1732..7aef5f63e8 100644 --- a/browser/src/Services/Explorer/ExplorerSelectors.ts +++ b/browser/src/Services/Explorer/ExplorerSelectors.ts @@ -35,6 +35,15 @@ export interface IFileNode { indentationLevel: number } +export const EmptyNode: ExplorerNode = { + type: null, + id: null, + modified: null, + filePath: null, + name: null, + indentationLevel: null, +} + export type ExplorerNode = IContainerNode | IFolderNode | IFileNode export const isPathExpanded = (state: IExplorerState, pathToCheck: string): boolean => { diff --git a/browser/src/Services/Explorer/ExplorerSplit.tsx b/browser/src/Services/Explorer/ExplorerSplit.tsx index 4544a0ebcb..c471a3752c 100644 --- a/browser/src/Services/Explorer/ExplorerSplit.tsx +++ b/browser/src/Services/Explorer/ExplorerSplit.tsx @@ -3,7 +3,6 @@ * */ -import { capitalize } from "lodash" import * as path from "path" import * as React from "react" import { Provider } from "react-redux" @@ -11,11 +10,8 @@ import { Store } from "redux" import { Event } from "oni-types" -// import { getInstance, IMenuBinding } from "./../../neovim/SharedNeovimInstance" - import { CallbackCommand, CommandManager } from "./../../Services/CommandManager" import { EditorManager } from "./../../Services/EditorManager" -// import { Configuration } from "./../../Services/Configuration" import { getInstance as NotificationsInstance } from "./../../Services/Notifications" import { windowManager } from "./../../Services/WindowManager" import { IWorkspace } from "./../../Services/Workspace" @@ -25,15 +21,11 @@ import { createStore, IExplorerState } from "./ExplorerStore" import * as ExplorerSelectors from "./ExplorerSelectors" import { Explorer } from "./ExplorerView" -import { mv, rm } from "shelljs" - type Node = ExplorerSelectors.ExplorerNode -type File = ExplorerSelectors.IFileNode export class ExplorerSplit { private _onEnterEvent: Event<void> = new Event<void>() private _selectedId: string = null - private _notifications = NotificationsInstance() private _store: Store<IExplorerState> @@ -51,7 +43,7 @@ export class ExplorerSplit { private _commandManager: CommandManager, private _editorManager: EditorManager, ) { - this._store = createStore() + this._store = createStore({ notifications: NotificationsInstance() }) this._workspace.onDirectoryChanged.subscribe(newDirectory => { this._store.dispatch({ @@ -70,10 +62,7 @@ export class ExplorerSplit { public enter(): void { this._store.dispatch({ type: "ENTER" }) - this._commandManager.registerCommand( - new CallbackCommand("explorer.delete", null, null, () => this._onDeleteItem()), - ) - + this._initialiseExplorerCommands() this._onEnterEvent.dispatch() } @@ -81,72 +70,9 @@ export class ExplorerSplit { this._store.dispatch({ type: "LEAVE" }) } - public sendExplorerNotification({ title, details }: { title: string; details: string }) { - const notification = this._notifications.createItem() - notification.setContents(title, details) - notification.setLevel("success") - notification.setExpiration(8000) - notification.show() - } - public moveFileOrFolder = (source: Node, dest: Node): void => { - if (!source || !dest) { - return - } - - let folderPath - let sourcePath - - if (source.type === "folder" && dest.type === "folder") { - return this.moveFolder(source, dest) - } - - if (dest.type === "file") { - const parent = this.findParentDir(dest.id) - folderPath = parent - } else if (dest.type === "container") { - folderPath = dest.name - } else { - folderPath = dest.folderPath - } - - if (folderPath && source.type === "file" && source.filePath) { - sourcePath = source.filePath - } else if (source.type === "folder" && folderPath) { - sourcePath = source.folderPath - } - - mv(sourcePath, folderPath) + this._store.dispatch({ type: "PASTE", pasted: [source], target: dest }) this._store.dispatch({ type: "REFRESH" }) - if (dest.type === "folder") { - this._store.dispatch({ type: "EXPAND_DIRECTORY", directoryPath: dest.folderPath }) - } - this.sendExplorerNotification({ - title: `${capitalize(source.type)} Moved`, - details: `Successfully moved ${source.name} to ${folderPath}`, - }) - } - - public moveFolder = ( - source: ExplorerSelectors.IFolderNode, - destination: ExplorerSelectors.IFolderNode, - ) => { - if (source.folderPath === destination.folderPath) { - return - } - mv(source.folderPath, destination.folderPath) - this._store.dispatch({ type: "REFRESH" }) - this._store.dispatch({ type: "EXPAND_DIRECTORY", directoryPath: destination.folderPath }) - this.sendExplorerNotification({ - title: `${capitalize(source.type)} Moved`, - details: `Successfully moved ${source.name} to ${destination.folderPath}`, - }) - } - - public findParentDir = (fileId: string): string => { - const { filePath } = this._getSelectedItem(fileId) as File - const folder = path.dirname(filePath) - return folder } public render(): JSX.Element { @@ -161,6 +87,60 @@ export class ExplorerSplit { ) } + private _initialiseExplorerCommands(): void { + this._commandManager.registerCommand( + new CallbackCommand("explorer.delete.persist", null, null, () => + this._onDeleteItem({ persist: true }), + ), + ) + this._commandManager.registerCommand( + new CallbackCommand("explorer.delete", null, null, () => + this._onDeleteItem({ persist: false }), + ), + ) + this._commandManager.registerCommand( + new CallbackCommand( + "explorer.yank", + "Yank Selected Item", + "Select a file to move", + () => this._onYankItem(), + ), + ) + + this._commandManager.registerCommand( + new CallbackCommand("explorer.undo", "Undo last explorer action", null, () => + this._onUndoItem(), + ), + ) + + this._commandManager.registerCommand( + new CallbackCommand( + "explorer.paste", + "Move/Paste Selected Item", + "Paste the last yanked item", + () => this._onPasteItem(), + ), + ) + + this._commandManager.registerCommand( + new CallbackCommand( + "explorer.expand.directory", + "Expand a selected directory", + null, + () => this._toggleDirectory("expand"), + ), + ) + + this._commandManager.registerCommand( + new CallbackCommand( + "explorer.collapse.directory", + "Collapse selected directory", + null, + () => this._toggleDirectory("collapse"), + ), + ) + } + private _onSelectionChanged(id: string): void { this._selectedId = id } @@ -196,14 +176,12 @@ export class ExplorerSplit { } } - private _getSelectedItem(id?: string): ExplorerSelectors.ExplorerNode { + private _getSelectedItem(id: string = this._selectedId): ExplorerSelectors.ExplorerNode { const state = this._store.getState() const nodes = ExplorerSelectors.mapStateToNodeList(state) - const idToUse = id || this._selectedId - - const items = nodes.filter(item => item.id === idToUse) + const items = nodes.filter(item => item.id === id) if (!items || !items.length) { return null @@ -212,26 +190,83 @@ export class ExplorerSplit { return items[0] } - private _onDeleteItem(): void { + private _getSelectedItemParent(filePath: string): ExplorerSelectors.ExplorerNode { + const state = this._store.getState() + const nodes = ExplorerSelectors.mapStateToNodeList(state) + const parentDir = path.dirname(filePath) + + const [parentNode] = nodes.filter( + item => + (item.type === "folder" && item.folderPath === parentDir) || + (item.type === "container" && item.name === parentDir), + ) + + return parentNode + } + + // This is different from on openItem since it only activates if the target is a folder + // also it means that each bound key only does one thing aka "h" collapses and "l" + // expands they are not toggles + private _toggleDirectory(action: "expand" | "collapse"): void { const selectedItem = this._getSelectedItem() + if (!selectedItem || selectedItem.type !== "folder") { + return + } + + const type = action === "expand" ? "EXPAND_DIRECTORY" : "COLLAPSE_DIRECTORY" + this._store.dispatch({ type, directoryPath: selectedItem.folderPath }) + } + private _onUndoItem(): void { + const { register: { undo } } = this._store.getState() + if (undo.length) { + this._store.dispatch({ type: "UNDO" }) + } + } + + private _onYankItem(): void { + const selectedItem = this._getSelectedItem() if (!selectedItem) { return } - switch (selectedItem.type) { - case "file": - rm(selectedItem.filePath) - break - case "folder": - rm("-rf", selectedItem.folderPath) - break - default: - alert("Not implemented yet") + const { register: { yank } } = this._store.getState() + const inYankRegister = yank.some(({ id }) => id === selectedItem.id) + + if (!inYankRegister) { + this._store.dispatch({ type: "YANK", target: selectedItem }) + } else { + this._store.dispatch({ type: "CLEAR_REGISTER", ids: [selectedItem.id] }) } + } - this._store.dispatch({ - type: "REFRESH", - }) + private _onPasteItem(): void { + const pasteTarget = this._getSelectedItem() + if (!pasteTarget) { + return + } + + const { register: { yank } } = this._store.getState() + + if (yank.length && pasteTarget) { + const sources = yank.map( + node => (node.type === "file" ? this._getSelectedItemParent(node.filePath) : node), + ) + this._store.dispatch({ + type: "PASTE", + target: pasteTarget, + pasted: yank, + sources, + }) + } + } + + private _onDeleteItem({ persist }: { persist: boolean }): void { + const selectedItem = this._getSelectedItem() + + if (!selectedItem) { + return + } + this._store.dispatch({ type: "DELETE", target: selectedItem, persist }) } } diff --git a/browser/src/Services/Explorer/ExplorerStore.ts b/browser/src/Services/Explorer/ExplorerStore.ts index 63d24153c8..72c8cbc0bb 100644 --- a/browser/src/Services/Explorer/ExplorerStore.ts +++ b/browser/src/Services/Explorer/ExplorerStore.ts @@ -4,15 +4,27 @@ * State management for the explorer split */ -import * as fs from "fs" - +import * as capitalize from "lodash/capitalize" +import * as last from "lodash/last" import * as omit from "lodash/omit" +import * as path from "path" + import { Reducer, Store } from "redux" import { combineEpics, createEpicMiddleware, Epic } from "redux-observable" +import { forkJoin } from "rxjs/observable/forkJoin" +import { fromPromise } from "rxjs/observable/fromPromise" +import { timer } from "rxjs/observable/timer" + +import * as Log from "./../../Log" import { createStore as createReduxStore } from "./../../Redux" +import { configuration } from "./../Configuration" +import { EmptyNode, ExplorerNode } from "./ExplorerSelectors" -import { FileSystem, IFileSystem } from "./ExplorerFileSystem" +import { Notifications } from "./../../Services/Notifications" +import { NotificationLevel } from "./../../Services/Notifications/NotificationStore" + +import { IFileSystem, OniFileSystem } from "./ExplorerFileSystem" export interface IFolderState { type: "folder" @@ -24,6 +36,13 @@ export const DefaultFolderState: IFolderState = { fullPath: null, } +export const DefaultRegisterState: IRegisterState = { + yank: [], + undo: [], + paste: EmptyNode, + updated: null, +} + export interface IFileState { type: "file" fullPath: string @@ -44,9 +63,20 @@ export interface OpenedFiles { [fullPath: string]: any } -export interface IFileSystem { - readdir(fullPath: string): Promise<FolderOrFile[]> - delete(fullPath: string): Promise<void> +export type RegisterAction = + | IPasteAction + | IDeleteSuccessAction + | IDeleteFailAction + | IDeleteAction + | IUndoAction + | IUndoSuccessAction + | IUndoFailAction + +interface IRegisterState { + yank: ExplorerNode[] + paste: ExplorerNode + undo: RegisterAction[] + updated: string[] } export interface IExplorerState { @@ -56,41 +86,299 @@ export interface IExplorerState { expandedFolders: ExpandedFolders hasFocus: boolean + register: IRegisterState } export const DefaultExplorerState: IExplorerState = { rootFolder: null, expandedFolders: {}, hasFocus: false, + register: DefaultRegisterState, +} + +export interface IUndoAction { + type: "UNDO" +} + +export interface IUndoSuccessAction { + type: "UNDO_SUCCESS" +} + +export interface IUndoFailAction { + type: "UNDO_FAIL" + reason: string +} + +export interface IYankAction { + type: "YANK" + path: string + target: ExplorerNode +} + +export interface IPasteAction { + type: "PASTE" + target: ExplorerNode + pasted: ExplorerNode[] + sources: ExplorerNode[] +} + +export interface IDeleteAction { + type: "DELETE" + target: ExplorerNode + persist: boolean +} + +export interface IDeleteSuccessAction { + type: "DELETE_SUCCESS" + target: ExplorerNode + persist: boolean +} + +export interface IDeleteFailAction { + type: "DELETE_FAIL" + reason: string +} + +export interface IClearRegisterAction { + type: "CLEAR_REGISTER" + ids: string[] +} + +export interface IExpandDirectoryAction { + type: "EXPAND_DIRECTORY" + directoryPath: string +} + +export interface IRefreshAction { + type: "REFRESH" +} + +export interface ISetRootDirectoryAction { + type: "SET_ROOT_DIRECTORY" + rootPath: string +} + +export interface ICollapseDirectory { + type: "COLLAPSE_DIRECTORY" + directoryPath: string +} + +export interface IExpandDirectoryResult { + type: "EXPAND_DIRECTORY_RESULT" + directoryPath: string + children: FolderOrFile[] +} + +export interface IEnterAction { + type: "ENTER" +} + +export interface ILeaveAction { + type: "LEAVE" +} + +export interface IPasteFailAction { + type: "PASTE_FAIL" + reason: string +} + +export interface IClearUpdateAction { + type: "CLEAR_UPDATE" +} + +export interface IPasteSuccessAction { + type: "PASTE_SUCCESS" + moved: IMovedNodes[] +} + +export interface IMovedNodes { + node: ExplorerNode + destination: string } export type ExplorerAction = - | { - type: "SET_ROOT_DIRECTORY" - rootPath: string - } - | { - type: "EXPAND_DIRECTORY" - directoryPath: string - } - | { - type: "COLLAPSE_DIRECTORY" - directoryPath: string - } - | { - type: "EXPAND_DIRECTORY_RESULT" - directoryPath: string - children: FolderOrFile[] - } - | { - type: "ENTER" - } - | { - type: "LEAVE" - } - | { - type: "REFRESH" - } + | IEnterAction + | ILeaveAction + | IExpandDirectoryResult + | ICollapseDirectory + | ISetRootDirectoryAction + | IExpandDirectoryAction + | IDeleteFailAction + | IRefreshAction + | IDeleteAction + | IDeleteSuccessAction + | IYankAction + | IPasteAction + | IPasteFailAction + | IPasteSuccessAction + | IClearUpdateAction + | IClearRegisterAction + | IUndoAction + | IUndoSuccessAction + | IUndoFailAction + +// Helper functions for Updating state ======================================================== +export const removePastedNode = (nodeArray: ExplorerNode[], ids: string[]): ExplorerNode[] => + nodeArray.filter(node => !ids.includes(node.id)) + +export const removeUndoItem = (undoArray: RegisterAction[]): RegisterAction[] => + undoArray.slice(0, undoArray.length - 1) + +const getSourceAndDestPaths = (source: ExplorerNode, dest: ExplorerNode) => { + const sourcePath = getPathForNode(source) + const destPath = dest.type === "file" ? path.dirname(dest.filePath) : getPathForNode(dest) + const destination = path.join(destPath, path.basename(sourcePath)) + return { source: sourcePath, destination } +} + +// Do not add un-undoable action to the undo list +export const shouldAddDeletion = (action: IDeleteSuccessAction) => (action.persist ? [action] : []) + +type Updates = IPasteSuccessAction | IDeleteSuccessAction | IUndoSuccessAction + +export const getUpdatedNode = (action: Updates, state?: IRegisterState): string[] => { + switch (action.type) { + case "PASTE_SUCCESS": + return action.moved.map(node => node.destination) + case "DELETE_SUCCESS": + return [getPathForNode(action.target)] + case "UNDO_SUCCESS": + const lastAction = last(state.undo) + + if (lastAction.type === "DELETE_SUCCESS") { + return [getPathForNode(lastAction.target)] + } else if (lastAction.type === "PASTE") { + return lastAction.pasted.map(node => getPathForNode(node)) + } + + return [] + default: + return [] + } +} + +const shouldExpandDirectory = (targets: ExplorerNode[]): IExpandDirectoryAction[] => + targets + .map(target => target.type !== "file" && Actions.expandDirectory(getPathForNode(target))) + .filter(Boolean) + +export const getPathForNode = (node: ExplorerNode) => { + if (node.type === "file") { + return node.filePath + } else if (node.type === "folder") { + return node.folderPath + } else { + return node.name + } +} + +// Strongly typed actions/action-creators to be used in multiple epics + +const Actions = { + Null: { type: null } as ExplorerAction, + + pasteSuccess: (moved: IMovedNodes[]) => + ({ type: "PASTE_SUCCESS", moved } as IPasteSuccessAction), + + pasteFail: (reason: string) => ({ type: "PASTE_FAIL", reason } as IPasteFailAction), + + undoFail: (reason: string) => ({ type: "UNDO_FAIL", reason } as IUndoFailAction), + + undoSuccess: { type: "UNDO_SUCCESS" } as IUndoSuccessAction, + + paste: { type: "PASTE" } as IPasteAction, + + refresh: { type: "REFRESH" } as IRefreshAction, + + deleteFail: (reason: string) => ({ type: "DELETE_FAIL", reason } as IDeleteFailAction), + + clearRegister: (ids: string[]) => ({ type: "CLEAR_REGISTER", ids } as IClearRegisterAction), + + clearUpdate: { type: "CLEAR_UPDATE" } as IClearUpdateAction, + + deleteSuccess: (target: ExplorerNode, persist: boolean): IDeleteSuccessAction => ({ + type: "DELETE_SUCCESS", + target, + persist, + }), + + expandDirectory: (directoryPath: string): IExpandDirectoryAction => ({ + type: "EXPAND_DIRECTORY", + directoryPath, + }), + + expandDirectoryResult: ( + pathToExpand: string, + sortedFilesAndFolders: FolderOrFile[], + ): ExplorerAction => { + return { + type: "EXPAND_DIRECTORY_RESULT", + directoryPath: pathToExpand, + children: sortedFilesAndFolders, + } + }, +} + +// Yank, Paste Delete register ============================= +// The undo register is essentially a list of past actions +// => [paste, delete, paste], when an action is carried out +// it is added to the back of the stack when an undo is triggered +// it is removed. +// The most recently actioned node(s) path(s) are set to the value of +// the updated field, this is used to animate updated fields, +// Updates are cleared shortly after to prevent re-animating + +export const yankRegisterReducer: Reducer<IRegisterState> = ( + state: IRegisterState = DefaultRegisterState, + action: ExplorerAction, +) => { + switch (action.type) { + case "YANK": + return { + ...state, + yank: [...state.yank, action.target], + } + case "PASTE": + return { + ...state, + paste: action.target, + undo: [...state.undo, action], + } + case "PASTE_SUCCESS": + return { + ...state, + updated: getUpdatedNode(action), + } + case "UNDO_SUCCESS": + return { + ...state, + undo: removeUndoItem(state.undo), + updated: getUpdatedNode(action, state), + } + case "CLEAR_REGISTER": + return { + ...state, + paste: EmptyNode, + yank: removePastedNode(state.yank, action.ids), + } + case "CLEAR_UPDATE": + return { + ...state, + updated: null, + } + case "DELETE_SUCCESS": + return { + ...state, + undo: [...state.undo, ...shouldAddDeletion(action)], + updated: getUpdatedNode(action), + } + case "LEAVE": + return { ...DefaultRegisterState, undo: state.undo } + case "DELETE_FAIL": + default: + return state + } +} export const rootFolderReducer: Reducer<IFolderState> = ( state: IFolderState = DefaultFolderState, @@ -151,25 +439,17 @@ export const reducer: Reducer<IExplorerState> = ( hasFocus: hasFocusReducer(state.hasFocus, action), rootFolder: rootFolderReducer(state.rootFolder, action), expandedFolders: expandedFolderReducer(state.expandedFolders, action), + register: yankRegisterReducer(state.register, action), } } -const NullAction: ExplorerAction = { type: null } as ExplorerAction - const setRootDirectoryEpic: Epic<ExplorerAction, IExplorerState> = (action$, store) => - action$.ofType("SET_ROOT_DIRECTORY").map(action => { - if (action.type !== "SET_ROOT_DIRECTORY") { - return NullAction - } - + action$.ofType("SET_ROOT_DIRECTORY").map((action: ISetRootDirectoryAction) => { if (!action.rootPath) { - return NullAction + return Actions.Null } - return { - type: "EXPAND_DIRECTORY", - directoryPath: action.rootPath, - } as ExplorerAction + return Actions.expandDirectory(action.rootPath) }) const sortFilesAndFoldersFunc = (a: FolderOrFile, b: FolderOrFile) => { @@ -186,25 +466,185 @@ const sortFilesAndFoldersFunc = (a: FolderOrFile, b: FolderOrFile) => { } } -const refreshEpic: Epic<ExplorerAction, IExplorerState> = (action$, store) => +// Send Notifications ================================================== +interface INotificationDetails { + title: string + details: string + level?: NotificationLevel +} + +const sendExplorerNotification = ( + { title, details, level = "success" }: INotificationDetails, + notifications: Notifications, +) => { + const notification = notifications.createItem() + notification.setContents(title, details) + notification.setLevel(level) + notification.setExpiration(8000) + notification.show() +} + +interface MoveNotificationArgs { + type: string + name: string + destination: string + notifications: Notifications +} +const moveNotification = ({ type, name, destination, notifications }: MoveNotificationArgs) => + sendExplorerNotification( + { + title: `${capitalize(type)} Moved`, + details: `Successfully moved ${name} to ${destination}`, + }, + notifications, + ) +interface SendNotificationArgs { + name: string + type: string + notifications: Notifications +} +const deletionNotification = ({ type, name, notifications }: SendNotificationArgs): void => + sendExplorerNotification( + { + title: `${capitalize(type)} deleted`, + details: `${name} was deleted successfully`, + }, + notifications, + ) + +interface ErrorNotificationArgs { + type: string + reason: string + notifications: Notifications +} + +const errorNotification = ({ type, reason, notifications }: ErrorNotificationArgs): void => + sendExplorerNotification( + { + title: `${capitalize(type)} Failed`, + details: reason, + level: "warn", + }, + notifications, + ) + +interface Dependencies { + fileSystem: IFileSystem + notifications: Notifications +} + +// EPICS ============================================================= +type ExplorerEpic = Epic<ExplorerAction, IExplorerState, Dependencies> + +export const pasteEpic: ExplorerEpic = (action$, store, { fileSystem }) => + action$.ofType("PASTE").mergeMap(({ target, pasted }: IPasteAction) => { + const ids = pasted.map(item => item.id) + const clearRegister = Actions.clearRegister(ids) + + return forkJoin( + pasted.map(async yankedItem => { + const { source, destination } = getSourceAndDestPaths(yankedItem, target) + await fileSystem.move(source, destination) + return { node: yankedItem, destination } + }), + ) + .flatMap(moved => { + return [ + clearRegister, + ...shouldExpandDirectory([target]), + Actions.refresh, + Actions.pasteSuccess(moved), + ] + }) + .catch(error => { + Log.warn(error) + return [clearRegister, Actions.pasteFail(error.message)] + }) + }) + +const successActions = (maybeDirsNodes: ExplorerNode[]) => [ + Actions.undoSuccess, + ...shouldExpandDirectory(maybeDirsNodes), + Actions.refresh, +] + +export const undoEpic: ExplorerEpic = (action$, store, { fileSystem }) => + action$.ofType("UNDO").mergeMap(action => { + const { register: { undo } } = store.getState() + const lastAction = last(undo) + + switch (lastAction.type) { + case "PASTE": + const { pasted, target: dir, sources } = lastAction + const filesAndFolders = pasted.map(file => getSourceAndDestPaths(file, dir)) + return fromPromise(fileSystem.moveNodesBack(filesAndFolders)) + .flatMap(() => successActions(sources)) + .catch(error => { + Log.warn(error) + return [Actions.undoFail("Sorry we can't undo the laste paste action")] + }) + + case "DELETE_SUCCESS": + const { target } = lastAction + return lastAction.persist + ? fromPromise(fileSystem.restoreNode(getPathForNode(target))) + .flatMap(() => successActions([target])) + .catch(error => { + Log.warn(error) + return [Actions.undoFail("The last deletion cannot be undone, sorry")] + }) + : [Actions.undoFail("The last deletion cannot be undone, sorry")] + default: + return [Actions.undoFail("Sorry we can't undo the last action")] + } + }) + +export const deleteEpic: ExplorerEpic = (action$, store, { fileSystem }) => + action$.ofType("DELETE").mergeMap((action: IDeleteAction) => { + const { target, persist } = action + const filepath = getPathForNode(target) + const maxSize = configuration.getValue("explorer.maxUndoFileSizeInBytes") + const persistEnabled = configuration.getValue("explorer.persistDeletedFiles") + const persistPromise = fileSystem.canPersistNode(filepath, maxSize) + + return fromPromise(persistPromise).flatMap(canPersistNode => + fromPromise( + persistEnabled && persist && canPersistNode + ? fileSystem.persistNode(filepath) + : fileSystem.deleteNode(target), + ) + .flatMap(() => [Actions.deleteSuccess(target, persist), Actions.refresh]) + .catch(error => { + Log.warn(error) + return [Actions.deleteFail(error.message)] + }), + ) + }) + +export const clearYankRegisterEpic: ExplorerEpic = (action$, store) => + action$.ofType("YANK").mergeMap((action: IYankAction) => { + const oneMinute = 60_000 + return timer(oneMinute).mapTo(Actions.clearRegister([action.target.id])) + }) + +export const clearUpdateEpic: ExplorerEpic = (action$, store) => + action$ + .ofType("PASTE_SUCCESS", "UNDO_SUCCESS", "DELETE_SUCCESS") + .mergeMap(() => timer(2_000).mapTo(Actions.clearUpdate)) + +const refreshEpic: ExplorerEpic = (action$, store) => action$.ofType("REFRESH").mergeMap(() => { const state = store.getState() return Object.keys(state.expandedFolders).map(p => { - return { - type: "EXPAND_DIRECTORY", - directoryPath: p, - } as ExplorerAction + return Actions.expandDirectory(p) }) }) -const expandDirectoryEpic = (fileSystem: IFileSystem): Epic<ExplorerAction, IExplorerState> => ( - action$, - store, -) => +const expandDirectoryEpic: ExplorerEpic = (action$, store, { fileSystem }) => action$.ofType("EXPAND_DIRECTORY").flatMap(async (action: ExplorerAction) => { if (action.type !== "EXPAND_DIRECTORY") { - return NullAction + return Actions.Null } const pathToExpand = action.directoryPath @@ -213,19 +653,66 @@ const expandDirectoryEpic = (fileSystem: IFileSystem): Epic<ExplorerAction, IExp const sortedFilesAndFolders = filesAndFolders.sort(sortFilesAndFoldersFunc) - return { - type: "EXPAND_DIRECTORY_RESULT", - directoryPath: pathToExpand, - children: sortedFilesAndFolders, - } as ExplorerAction + return Actions.expandDirectoryResult(pathToExpand, sortedFilesAndFolders) }) -export const createStore = (fileSystem?: IFileSystem): Store<IExplorerState> => { - fileSystem = fileSystem || new FileSystem(fs) +export const notificationEpic: ExplorerEpic = (action$, store, { notifications }) => + action$.ofType("PASTE_SUCCESS", "DELETE_SUCCESS", "PASTE_FAIL", "DELETE_FAIL").map(action => { + switch (action.type) { + case "PASTE_SUCCESS": + action.moved.map(item => + moveNotification({ + notifications, + type: item.node.type, + name: item.node.name, + destination: item.destination, + }), + ) + return Actions.Null + case "DELETE_SUCCESS": + deletionNotification({ + notifications, + type: action.target.type, + name: action.target.name, + }) + return Actions.Null + case "PASTE_FAIL": + case "DELETE_FAIL": + const [type] = action.type.split("_") + errorNotification({ + type, + notifications, + reason: action.reason, + }) + return Actions.Null + default: + return Actions.Null + } + }) + +interface ICreateStore { + fileSystem?: IFileSystem + notifications: Notifications +} +export const createStore = ({ + fileSystem = OniFileSystem, + notifications, +}: ICreateStore): Store<IExplorerState> => { return createReduxStore("Explorer", reducer, DefaultExplorerState, [ - createEpicMiddleware( - combineEpics(setRootDirectoryEpic, expandDirectoryEpic(fileSystem), refreshEpic), + createEpicMiddleware<ExplorerAction, IExplorerState, Dependencies>( + combineEpics( + refreshEpic, + setRootDirectoryEpic, + clearUpdateEpic, + clearYankRegisterEpic, + pasteEpic, + undoEpic, + deleteEpic, + expandDirectoryEpic, + notificationEpic, + ), + { dependencies: { fileSystem, notifications } }, ), ]) } diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index 4019e0de8f..949fac7ba0 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -9,10 +9,11 @@ import HTML5Backend from "react-dnd-html5-backend" import { connect } from "react-redux" import { compose } from "redux" -// import { Transition, TransitionGroup } from "react-transition-group" +import { CSSTransition, TransitionGroup } from "react-transition-group" import { styled } from "./../../UI/components/common" import { SidebarContainerView, SidebarItemView } from "./../../UI/components/SidebarItemView" +import { Sneakable } from "./../../UI/components/Sneakable" import { VimNavigator } from "./../../UI/components/VimNavigator" import { DragAndDrop, Droppeable } from "./../DragAndDrop" @@ -28,6 +29,8 @@ export interface INodeViewProps { node: ExplorerSelectors.ExplorerNode isSelected: boolean onClick: () => void + yanked: string[] + updated?: string[] } const NodeWrapper = styled.div` @@ -65,6 +68,31 @@ interface IMoveNode { } } +const NodeTransitionWrapper = styled.div` + transition: all 400ms 50ms ease-in-out; + + &.move-enter { + opacity: 0.01; + transform: scale(0.9); + } + + &.move-enter-active { + transform: scale(1); + opacity: 1; + } +` + +interface ITransitionProps { + children: React.ReactNode + updated: boolean +} + +const Transition = ({ children, updated }: ITransitionProps) => ( + <CSSTransition in={updated} classNames="move" timeout={1000}> + <NodeTransitionWrapper className={updated && "move"}>{children}</NodeTransitionWrapper> + </CSSTransition> +) + export class NodeView extends React.PureComponent<INodeViewProps, {}> { public moveFileOrFolder = ({ drag, drop }: IMoveNode) => { this.props.moveFileOrFolder(drag.node, drop.node) @@ -85,8 +113,12 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { ) } + public hasUpdated = (path: string) => + !!this.props.updated && this.props.updated.some(nodePath => nodePath === path) + public getElement(): JSX.Element { const { node } = this.props + const yanked = this.props.yanked.includes(node.id) switch (node.type) { case "file": @@ -98,18 +130,23 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { isValidDrop={this.isSameNode} node={node} render={({ canDrop, isDragging, didDrop, isOver }) => { + const updated = this.hasUpdated(node.filePath) return ( - <SidebarItemView - isOver={isOver && canDrop} - didDrop={didDrop} - canDrop={canDrop} - onClick={stopPropagation(() => this.props.onClick())} - text={node.name} - isFocused={this.props.isSelected} - isContainer={false} - indentationLevel={node.indentationLevel} - icon={<FileIcon fileName={node.name} isLarge={true} />} - /> + <Transition updated={updated}> + <SidebarItemView + updated={updated} + yanked={yanked} + isOver={isOver && canDrop} + didDrop={didDrop} + canDrop={canDrop} + text={node.name} + isFocused={this.props.isSelected} + isContainer={false} + indentationLevel={node.indentationLevel} + onClick={stopPropagation(this.props.onClick)} + icon={<FileIcon fileName={node.name} isLarge={true} />} + /> + </Transition> ) }} /> @@ -123,12 +160,13 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { render={({ isOver }) => { return ( <SidebarContainerView + yanked={yanked} isOver={isOver} isContainer={true} isExpanded={node.expanded} - onClick={stopPropagation(() => this.props.onClick())} text={node.name} isFocused={this.props.isSelected} + onClick={stopPropagation(this.props.onClick)} /> ) }} @@ -143,17 +181,22 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { onDrop={this.moveFileOrFolder} node={node} render={({ isOver, didDrop, canDrop }) => { + const updated = this.hasUpdated(node.folderPath) return ( - <SidebarContainerView - didDrop={didDrop} - isOver={isOver && canDrop} - isContainer={false} - isExpanded={node.expanded} - text={node.name} - isFocused={this.props.isSelected} - indentationLevel={node.indentationLevel} - onClick={stopPropagation(() => this.props.onClick())} - /> + <Transition updated={updated}> + <SidebarContainerView + yanked={yanked} + updated={updated} + didDrop={didDrop} + isOver={isOver && canDrop} + isContainer={false} + isExpanded={node.expanded} + text={node.name} + isFocused={this.props.isSelected} + indentationLevel={node.indentationLevel} + onClick={stopPropagation(this.props.onClick)} + /> + </Transition> ) }} /> @@ -168,11 +211,13 @@ export interface IExplorerViewContainerProps { moveFileOrFolder: (source: Node, dest: Node) => void onSelectionChanged: (id: string) => void onClick: (id: string) => void + yanked?: string[] } export interface IExplorerViewProps extends IExplorerViewContainerProps { nodes: ExplorerSelectors.ExplorerNode[] isActive: boolean + updated: string[] } import { SidebarEmptyPaneView } from "./../../UI/components/SidebarEmptyPaneView" @@ -195,28 +240,34 @@ export class ExplorerView extends React.PureComponent<IExplorerViewProps, {}> { } return ( - <VimNavigator - ids={ids} - active={this.props.isActive} - onSelectionChanged={this.props.onSelectionChanged} - onSelected={id => this.props.onClick(id)} - render={(selectedId: string) => { - const nodes = this.props.nodes.map(node => ( - <NodeView - moveFileOrFolder={this.props.moveFileOrFolder} - node={node} - isSelected={node.id === selectedId} - onClick={() => this.props.onClick(node.id)} - /> - )) - - return ( - <div className="explorer enable-mouse"> - <div className="items">{nodes}</div> - </div> - ) - }} - /> + <TransitionGroup> + <VimNavigator + ids={ids} + active={this.props.isActive} + onSelectionChanged={this.props.onSelectionChanged} + onSelected={id => this.props.onClick(id)} + render={(selectedId: string) => { + const nodes = this.props.nodes.map(node => ( + <Sneakable callback={() => this.props.onClick(node.id)} key={node.id}> + <NodeView + updated={this.props.updated} + yanked={this.props.yanked} + moveFileOrFolder={this.props.moveFileOrFolder} + node={node} + isSelected={node.id === selectedId} + onClick={() => this.props.onClick(node.id)} + /> + </Sneakable> + )) + + return ( + <div className="explorer enable-mouse"> + <div className="items">{nodes}</div> + </div> + ) + }} + /> + </TransitionGroup> ) } } @@ -225,10 +276,13 @@ const mapStateToProps = ( state: IExplorerState, containerProps: IExplorerViewContainerProps, ): IExplorerViewProps => { + const yanked = state.register.yank.map(node => node.id) return { ...containerProps, isActive: state.hasFocus, nodes: ExplorerSelectors.mapStateToNodeList(state), + updated: state.register.updated, + yanked, } } diff --git a/browser/src/Services/Sidebar/SidebarStore.ts b/browser/src/Services/Sidebar/SidebarStore.ts index c1d73cd655..61029044e9 100644 --- a/browser/src/Services/Sidebar/SidebarStore.ts +++ b/browser/src/Services/Sidebar/SidebarStore.ts @@ -54,6 +54,10 @@ export class SidebarManager { return this._store.getState().entries } + get isFocused(): boolean { + return this._contentSplit.isFocused + } + public get store(): Store<ISidebarState> { return this._store } diff --git a/browser/src/UI/components/SidebarItemView.tsx b/browser/src/UI/components/SidebarItemView.tsx index ed1009d3f0..d1378a0993 100644 --- a/browser/src/UI/components/SidebarItemView.tsx +++ b/browser/src/UI/components/SidebarItemView.tsx @@ -11,6 +11,8 @@ import { styled, withProps } from "./common" import { Sneakable } from "./../../UI/components/Sneakable" export interface ISidebarItemViewProps { + yanked?: boolean + updated?: boolean isOver?: boolean canDrop?: boolean didDrop?: boolean @@ -28,10 +30,12 @@ const SidebarItemStyleWrapper = withProps<ISidebarItemViewProps>(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 ${props.theme["highlight.mode.normal.background"]}` : "4px solid transparent"}; - ${p => p.isOver && `border: 3px solid ${p.theme["highlight.mode.insert.background"]};`}; + ${p => + (p.isOver || p.yanked) && + `border: 3px solid ${p.theme["highlight.mode.insert.background"]};`}; display: flex; flex-direction: row; justify-content: center; @@ -99,6 +103,8 @@ export class SidebarItemView extends React.PureComponent<ISidebarItemViewProps, } export interface ISidebarContainerViewProps extends IContainerProps { + yanked?: boolean + updated?: boolean didDrop?: boolean text: string isExpanded: boolean @@ -111,10 +117,14 @@ export interface ISidebarContainerViewProps extends IContainerProps { interface IContainerProps { isOver?: boolean canDrop?: boolean + yanked?: boolean + updated?: boolean } const SidebarContainer = withProps<IContainerProps>(styled.div)` - ${p => p.isOver && `border: 3px solid ${p.theme["highlight.mode.insert.background"]};`}; + ${p => + (p.isOver || p.yanked) && + `border: 3px solid ${p.theme["highlight.mode.insert.background"]};`}; ` export class SidebarContainerView extends React.PureComponent<ISidebarContainerViewProps, {}> { @@ -127,8 +137,15 @@ export class SidebarContainerView extends React.PureComponent<ISidebarContainerV const indentationlevel = this.props.indentationLevel || 0 return ( - <SidebarContainer canDrop={this.props.canDrop} isOver={this.props.isOver}> + <SidebarContainer + updated={this.props.updated} + yanked={this.props.yanked} + canDrop={this.props.canDrop} + isOver={this.props.isOver} + > <SidebarItemView + yanked={this.props.yanked} + updated={this.props.updated} didDrop={this.props.didDrop} indentationLevel={indentationlevel} icon={icon} diff --git a/browser/src/Utility.ts b/browser/src/Utility.ts index 20f9cf890b..c496436b87 100644 --- a/browser/src/Utility.ts +++ b/browser/src/Utility.ts @@ -245,15 +245,3 @@ export function ignoreWhilePendingPromise<T, U>( return ret } - -export function checkIfFileExistsSync(filename: string): boolean | Error { - try { - return fs.statSync(filename).isFile() - } catch (e) { - if (e.code === "ENOENT") { - return false - } else { - throw e - } - } -} diff --git a/browser/src/neovim/NeovimInstance.ts b/browser/src/neovim/NeovimInstance.ts index 130d98aa27..53ea8f940f 100644 --- a/browser/src/neovim/NeovimInstance.ts +++ b/browser/src/neovim/NeovimInstance.ts @@ -1,4 +1,5 @@ import { EventEmitter } from "events" +import { pathExistsSync } from "fs-extra" import * as path from "path" import * as mkdirp from "mkdirp" @@ -14,8 +15,6 @@ import { addDefaultUnitIfNeeded, measureFont } from "./../Font" import * as Platform from "./../Platform" import { Configuration } from "./../Services/Configuration" -import { checkIfFileExistsSync } from "./../Utility" - import * as Actions from "./actions" import { NeovimBufferReference } from "./MsgPack" import { INeovimAutoCommands, NeovimAutoCommands } from "./NeovimAutoCommands" @@ -569,7 +568,7 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { public doesInitVimExist(): string { const initVimPath = this.getInitVimPath() try { - return checkIfFileExistsSync(initVimPath) ? initVimPath : null + return pathExistsSync(initVimPath) ? initVimPath : null } catch (e) { return null } diff --git a/browser/test/Services/Explorer/ExplorerFileSystemTests.ts b/browser/test/Services/Explorer/ExplorerFileSystemTests.ts new file mode 100644 index 0000000000..0255214c43 --- /dev/null +++ b/browser/test/Services/Explorer/ExplorerFileSystemTests.ts @@ -0,0 +1,77 @@ +import * as assert from "assert" +import { emptyDir, mkdirp, remove, stat, writeFile } from "fs-extra" +import * as os from "os" +import * as path from "path" + +import { FileSystem, OniFileSystem } from "./../../../src/Services/Explorer/ExplorerFileSystem" + +describe("File System tests", async () => { + let rootPath: string + let filePath: string + let secondPath: string + let fileSystem: FileSystem + + before(async () => { + rootPath = path.normalize(path.join(os.tmpdir(), "a", "test", "dir")) + filePath = path.join(rootPath, "file.txt") + secondPath = path.join(rootPath, "file1.txt") + await mkdirp(rootPath) + fileSystem = OniFileSystem + }) + + beforeEach(async () => { + await Promise.all([ + emptyDir(fileSystem.backupDir), + writeFile(filePath, "hello world"), + writeFile(secondPath, "file1.txt"), + ]) + }) + + after(async () => { + await remove(rootPath) + }) + + it("Should return false is the file is too big to persist", async () => { + const canPersist = await fileSystem.canPersistNode(filePath, 1) + assert.ok(!canPersist) + }) + it("Should return true is the file can be persisted", async () => { + const canPersist = await fileSystem.canPersistNode(filePath, 1000) + assert.ok(canPersist) + }) + it("Should delete the file", async () => { + await fileSystem.deleteNode({ + filePath: secondPath, + id: "2", + type: "file", + modified: false, + name: "file1", + indentationLevel: 2, + }) + try { + await stat(secondPath) + } catch (e) { + assert.ok(e.message.includes("ENOENT")) + } + }) + + it("Should persist the file", async () => { + await fileSystem.persistNode(secondPath) + const stats = await stat(path.join(fileSystem.backupDir, "file1.txt")) + assert.ok(stats.isFile()) + }) + + it("Should move a collection of files to the correct directory", async () => { + const locationOne = path.join(fileSystem.backupDir, "file.txt") + const locationTwo = path.join(fileSystem.backupDir, "file1.txt") + const nodes = [ + { source: locationOne, destination: filePath }, + { source: locationTwo, destination: secondPath }, + ] + await fileSystem.moveNodesBack(nodes) + const firstStats = await stat(locationOne) + const secondStats = await stat(locationTwo) + assert.ok(firstStats.isFile()) + assert.ok(secondStats.isFile()) + }) +}) diff --git a/browser/test/Services/Explorer/ExplorerStoreTests.ts b/browser/test/Services/Explorer/ExplorerStoreTests.ts index 5e2b95f873..46885ba3fe 100644 --- a/browser/test/Services/Explorer/ExplorerStoreTests.ts +++ b/browser/test/Services/Explorer/ExplorerStoreTests.ts @@ -6,13 +6,19 @@ import * as assert from "assert" import * as path from "path" import { Store } from "redux" +import { MockStoreCreator } from "redux-mock-store" +import { ActionsObservable, combineEpics, createEpicMiddleware } from "redux-observable" import * as ExplorerFileSystem from "./../../../src/Services/Explorer/ExplorerFileSystem" +import { ExplorerNode } from "./../../../src/Services/Explorer/ExplorerSelectors" import * as ExplorerState from "./../../../src/Services/Explorer/ExplorerStore" +import { Notifications } from "./../../../src/Services/Notifications/Notifications" +import * as clone from "lodash/clone" +import * as head from "lodash/head" import * as TestHelpers from "./../../TestHelpers" -const MemoryFileSystem = require("memory-fs") // tslint:disable-line +const configureMockStore = require("redux-mock-store") // tslint:disable-line export class MockedFileSystem implements ExplorerFileSystem.IFileSystem { public promises: Array<Promise<any>> @@ -32,8 +38,31 @@ export class MockedFileSystem implements ExplorerFileSystem.IFileSystem { this.promises.push(promise) return promise } + + public async canPersistNode() { + return true + } + + // tslint:disable + public async restoreNode() {} + public async persistNode() {} + public async moveNodesBack(): Promise<void> {} + public async deleteNode(): Promise<void> {} + public async move(source: string, destination: string): Promise<void> {} + // tslint:enable } +const rootEpic = combineEpics(ExplorerState.clearYankRegisterEpic, ExplorerState.pasteEpic) + +const epicMiddleware = createEpicMiddleware(rootEpic, { + dependencies: { fileSystem: MockedFileSystem as any, notifications: {} as Notifications }, +}) + +const MemoryFileSystem = require("memory-fs") // tslint:disable-line +const mockStore: MockStoreCreator<ExplorerState.IExplorerState> = configureMockStore([ + epicMiddleware, +]) + describe("ExplorerStore", () => { let fileSystem: any let store: Store<ExplorerState.IExplorerState> @@ -41,6 +70,41 @@ describe("ExplorerStore", () => { const rootPath = path.normalize(path.join(TestHelpers.getRootDirectory(), "a", "test", "dir")) const filePath = path.join(rootPath, "file.txt") + const target = { filePath, id: "1" } + const epicStore = mockStore({ ...ExplorerState.DefaultExplorerState }) + + const pasted1 = { + type: "file", + filePath: "/test/dir/afile.txt", + id: "1", + } + + const target1 = { + type: "folder", + folderPath: "/test/dir/subdir/", + id: "1", + } + + const deleteAction = { + type: "DELETE_SUCCESS", + persist: true, + path: "/test/dir", + target: { + type: "folder", + folderPath: "/test/dir/subdir", + id: "2", + expanded: false, + name: "subdir", + indentationLevel: 2, + }, + } as ExplorerState.IDeleteSuccessAction + + const pasteAction = { + type: "PASTE", + target: target1, + pasted: [pasted1], + sources: [pasted1], + } as ExplorerState.IPasteAction beforeEach(() => { fileSystem = new MemoryFileSystem() @@ -50,7 +114,14 @@ describe("ExplorerStore", () => { explorerFileSystem = new MockedFileSystem( new ExplorerFileSystem.FileSystem(fileSystem as any), ) - store = ExplorerState.createStore(explorerFileSystem) + store = ExplorerState.createStore({ + fileSystem: explorerFileSystem, + notifications: {} as any, + }) + }) + + afterEach(() => { + epicMiddleware.replaceEpic(rootEpic) }) describe("SET_ROOT_DIRECTORY", () => { @@ -73,4 +144,291 @@ describe("ExplorerStore", () => { ) }) }) + + describe("YANK_AND_PASTE_EPICS", async () => { + const fs = { + move: async (source, dest) => null, + readdir: () => null as any, + exists: async file => true, + persistNode: async file => null, + restoreNode: async file => null, + deleteNode: file => null, + canPersistNode: async (file, size) => true, + moveNodesBack: async collection => null, + } as ExplorerFileSystem.IFileSystem + + const notifications = {} as Notifications + + it("dispatches a clear register action after a minute", async () => { + epicStore.dispatch({ type: "YANK", target }) + const actions = epicStore.getActions() + await TestHelpers.waitForAllAsyncOperations() + // three because an init action is sent first + await assert.ok(actions.length === 3) + const clearedRegister = !!actions.find(action => action.type === "CLEAR_REGISTER") + assert.ok(clearedRegister) + }) + + it("should dispatch a paste success upon pasting successfully", done => { + const action$ = ActionsObservable.of({ + type: "PASTE", + target: target1, + pasted: [pasted1], + sources: [pasted1], + } as ExplorerState.ExplorerAction) + + const expected = [ + { type: "CLEAR_REGISTER", ids: ["1"] }, + { type: "EXPAND_DIRECTORY", directoryPath: target1.folderPath }, + { type: "REFRESH" }, + { + type: "PASTE_SUCCESS", + moved: [ + { destination: path.join(target1.folderPath, "afile.txt"), node: pasted1 }, + ], + }, + ] + + ExplorerState.pasteEpic(action$, null, { + fileSystem: fs, + notifications, + }) + .toArray() + .subscribe(actualActions => { + assert.ok(actualActions.find(action => action.type === "PASTE_SUCCESS")) + assert.deepEqual(actualActions, expected) + done() + }) + }) + + it("should correctly trigger a node deletion", () => { + const action$ = ActionsObservable.of({ + type: "DELETE", + target: target1, + persist: true, + } as ExplorerState.IDeleteAction) + + const expected = [ + { type: "DELETE_SUCCESS", target: target1, persist: true }, + { type: "REFRESH" }, + ] + + ExplorerState.deleteEpic(action$, null, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) + + it("should correctly dispatch a fail action if there is an error", () => { + const action$ = ActionsObservable.of({ + type: "DELETE", + target: target1, + persist: true, + } as ExplorerState.IDeleteAction) + + const expected = [{ type: "DELETE_FAIL", reason: "Doesnt work" }] + + ExplorerState.deleteEpic(action$, null, { + fileSystem: { + ...fs, + persistNode: async node => { + throw new Error("Doesnt work") + }, + }, + notifications, + }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) + + it("Should correctly trigger a move action on undo of paste", () => { + const action$ = ActionsObservable.of({ + type: "UNDO", + } as ExplorerState.ExplorerAction) + + const stateCopy = clone(ExplorerState.DefaultExplorerState) + const state = { + ...stateCopy, + register: { + ...stateCopy.register, + undo: [pasteAction], + }, + } + + const undoState = mockStore(state) + const expected = [{ type: "UNDO_SUCCESS" }, { type: "REFRESH" }] + + ExplorerState.undoEpic(action$, undoState, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) + + it("Should trigger an expand directory on undo if the original source is a directory", () => { + const action$ = ActionsObservable.of({ + type: "UNDO", + } as ExplorerState.ExplorerAction) + + const stateCopy = clone(ExplorerState.DefaultExplorerState) + const state = { + ...stateCopy, + register: { + ...stateCopy.register, + undo: [{ ...pasteAction, sources: [target1] as ExplorerNode[] }], + }, + } + + const undoState = mockStore(state) + const expected = [ + { type: "UNDO_SUCCESS" }, + { type: "EXPAND_DIRECTORY", directoryPath: "/test/dir/subdir/" }, + { type: "REFRESH" }, + ] + + ExplorerState.undoEpic(action$, undoState, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) + + it("Should trigger a restore action if the deleted note can be restored", () => { + const action$ = ActionsObservable.of({ + type: "UNDO", + } as ExplorerState.ExplorerAction) + + const stateCopy = clone(ExplorerState.DefaultExplorerState) + const state = { + ...stateCopy, + register: { + ...stateCopy.register, + undo: [deleteAction], + }, + } + + const undoState = mockStore(state) + const expected = [ + { type: "UNDO_SUCCESS" }, + { type: "EXPAND_DIRECTORY", directoryPath: "/test/dir/subdir" }, + { type: "REFRESH" }, + ] + + ExplorerState.undoEpic(action$, undoState, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) + + it("Should return a fail action if the node was truly deleted", () => { + const action$ = ActionsObservable.of({ + type: "UNDO", + } as ExplorerState.ExplorerAction) + + const stateCopy = clone(ExplorerState.DefaultExplorerState) + const state = { + ...stateCopy, + register: { + ...stateCopy.register, + undo: [{ ...deleteAction, persist: false }], + }, + } + + const undoState = mockStore(state) + const expected = [ + { + type: "UNDO_FAIL", + reason: "The last deletion cannot be undone, sorry", + } as ExplorerState.IUndoFailAction, + ] + + ExplorerState.undoEpic(action$, undoState, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) + + it("Should clear updates after a short interval", () => { + const action$ = ActionsObservable.of(deleteAction) + + const expected = [ + { + type: "CLEAR_UPDATE", + } as ExplorerState.IClearUpdateAction, + ] + + ExplorerState.clearUpdateEpic(action$, null, { + fileSystem: fs, + notifications, + }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) + }) + + describe("Store utility helper tests", () => { + it("Should not add an action if it isn't set to persist", () => { + const testAction = { + type: "DELETE_SUCCESS", + persist: false, + target: { id: "2", type: "file", filePath }, + } as ExplorerState.IDeleteSuccessAction + const newState = ExplorerState.shouldAddDeletion(testAction) + assert.ok(newState.length === 0 && Array.isArray(newState)) + }) + + it("Should return an action if it is set to persist", () => { + const testAction = { + type: "DELETE_SUCCESS", + persist: true, + target: { id: "2", type: "file", filePath }, + } as ExplorerState.IDeleteSuccessAction + const newState = ExplorerState.shouldAddDeletion(testAction) + assert.deepEqual(head(newState), testAction) + }) + describe("Register Reducer test", () => { + const { yankRegisterReducer, DefaultExplorerState: { register } } = ExplorerState + + it("It should add paste items to both the paste and undo registers", () => { + const newState = yankRegisterReducer(clone(register), pasteAction) + assert.deepEqual( + newState.paste, + pasteAction.target, + "Paste is set to the node which was the target of the paste action", + ) + assert.deepEqual( + head(newState.undo), + pasteAction, + "The paste action is saved in the undo queue", + ) + }) + + it("Should remove item from the end of the undo list following undo success", () => { + const state = { ...register, undo: [pasteAction] } + const action = { type: "UNDO_SUCCESS" } + const newState = yankRegisterReducer(state, action) + assert.ok(!newState.undo.length) + }) + + it("Adds a delete action to the undo register IF it can be persisted)", () => { + const newState = yankRegisterReducer(clone(register), deleteAction) + assert.deepEqual(head(newState.undo), deleteAction) + }) + + it("Does NOT Add a delete action to the undo register IF it can't be persisted)", () => { + const newState = yankRegisterReducer(clone(register), { + ...deleteAction, + persist: false, + }) + assert.ok(!newState.undo.length) + }) + }) + }) }) diff --git a/jest.config.js b/jest.config.js index 5d0d3713a9..646aba48e8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,9 @@ module.exports = { + bail: true, verbose: true, collectCoverage: true, - collectCoverageFrom: ["**/*.{tsx}", "!**/node_modules/**", "!**/dist/**"], + coverageDirectory: "<rootDir>/coverage/", + collectCoverageFrom: ["**/components/*.{tsx}", "!**/node_modules/**", "!**/dist/**"], setupFiles: ["<rootDir>/ui-tests/jestsetup.ts"], moduleNameMapper: { electron: "<rootDir>/ui-tests/mocks/electronMock.ts", diff --git a/package.json b/package.json index d2c2c95ec7..f7a1f7b82e 100644 --- a/package.json +++ b/package.json @@ -5,14 +5,7 @@ "homepage": "https://www.onivim.io", "version": "0.3.3", "description": "Code editor with a modern twist on modal editing - powered by neovim.", - "keywords": [ - "vim", - "neovim", - "text", - "editor", - "ide", - "vim" - ], + "keywords": ["vim", "neovim", "text", "editor", "ide", "vim"], "main": "./lib/main/src/main.js", "bin": { "oni": "./cli/oni", @@ -51,39 +44,23 @@ "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": [ { "name": "ADA source", "role": "Editor", - "ext": [ - "adb", - "ads" - ] + "ext": ["adb", "ads"] }, { "name": "Compiled AppleScript", @@ -103,20 +80,12 @@ { "name": "ASP document", "role": "Editor", - "ext": [ - "asp", - "asa" - ] + "ext": ["asp", "asa"] }, { "name": "ASP.NET document", "role": "Editor", - "ext": [ - "aspx", - "ascx", - "asmx", - "ashx" - ] + "ext": ["aspx", "ascx", "asmx", "ashx"] }, { "name": "BibTeX bibliography", @@ -131,13 +100,7 @@ { "name": "C++ source", "role": "Editor", - "ext": [ - "cc", - "cp", - "cpp", - "cxx", - "c++" - ] + "ext": ["cc", "cp", "cpp", "cxx", "c++"] }, { "name": "C# source", @@ -162,10 +125,7 @@ { "name": "Clojure source", "role": "Editor", - "ext": [ - "clj", - "cljs" - ] + "ext": ["clj", "cljs"] }, { "name": "Comma separated values", @@ -180,20 +140,12 @@ { "name": "CGI script", "role": "Editor", - "ext": [ - "cgi", - "fcgi" - ] + "ext": ["cgi", "fcgi"] }, { "name": "Configuration file", "role": "Editor", - "ext": [ - "cfg", - "conf", - "config", - "htaccess" - ] + "ext": ["cfg", "conf", "config", "htaccess"] }, { "name": "Cascading style sheet", @@ -218,10 +170,7 @@ { "name": "Erlang source", "role": "Editor", - "ext": [ - "erl", - "hrl" - ] + "ext": ["erl", "hrl"] }, { "name": "F-Script source", @@ -231,32 +180,17 @@ { "name": "Fortran source", "role": "Editor", - "ext": [ - "f", - "for", - "fpp", - "f77", - "f90", - "f95" - ] + "ext": ["f", "for", "fpp", "f77", "f90", "f95"] }, { "name": "Header", "role": "Editor", - "ext": [ - "h", - "pch" - ] + "ext": ["h", "pch"] }, { "name": "C++ header", "role": "Editor", - "ext": [ - "hh", - "hpp", - "hxx", - "h++" - ] + "ext": ["hh", "hpp", "hxx", "h++"] }, { "name": "Go source", @@ -266,28 +200,17 @@ { "name": "GTD document", "role": "Editor", - "ext": [ - "gtd", - "gtdlog" - ] + "ext": ["gtd", "gtdlog"] }, { "name": "Haskell source", "role": "Editor", - "ext": [ - "hs", - "lhs" - ] + "ext": ["hs", "lhs"] }, { "name": "HTML document", "role": "Editor", - "ext": [ - "htm", - "html", - "phtml", - "shtml" - ] + "ext": ["htm", "html", "phtml", "shtml"] }, { "name": "Include file", @@ -327,10 +250,7 @@ { "name": "JavaScript source", "role": "Editor", - "ext": [ - "js", - "htc" - ] + "ext": ["js", "htc"] }, { "name": "Java Server Page", @@ -355,14 +275,7 @@ { "name": "Lisp source", "role": "Editor", - "ext": [ - "lisp", - "cl", - "l", - "lsp", - "mud", - "el" - ] + "ext": ["lisp", "cl", "l", "lsp", "mud", "el"] }, { "name": "Log file", @@ -382,12 +295,7 @@ { "name": "Markdown document", "role": "Editor", - "ext": [ - "markdown", - "mdown", - "markdn", - "md" - ] + "ext": ["markdown", "mdown", "markdn", "md"] }, { "name": "Makefile source", @@ -397,29 +305,17 @@ { "name": "Mediawiki document", "role": "Editor", - "ext": [ - "wiki", - "wikipedia", - "mediawiki" - ] + "ext": ["wiki", "wikipedia", "mediawiki"] }, { "name": "MIPS assembler source", "role": "Editor", - "ext": [ - "s", - "mips", - "spim", - "asm" - ] + "ext": ["s", "mips", "spim", "asm"] }, { "name": "Modula-3 source", "role": "Editor", - "ext": [ - "m3", - "cm3" - ] + "ext": ["m3", "cm3"] }, { "name": "MoinMoin document", @@ -439,28 +335,17 @@ { "name": "OCaml source", "role": "Editor", - "ext": [ - "ml", - "mli", - "mll", - "mly" - ] + "ext": ["ml", "mli", "mll", "mly"] }, { "name": "Mustache document", "role": "Editor", - "ext": [ - "mustache", - "hbs" - ] + "ext": ["mustache", "hbs"] }, { "name": "Pascal source", "role": "Editor", - "ext": [ - "pas", - "p" - ] + "ext": ["pas", "p"] }, { "name": "Patch file", @@ -470,11 +355,7 @@ { "name": "Perl source", "role": "Editor", - "ext": [ - "pl", - "pod", - "perl" - ] + "ext": ["pl", "pod", "perl"] }, { "name": "Perl module", @@ -484,80 +365,47 @@ { "name": "PHP source", "role": "Editor", - "ext": [ - "php", - "php3", - "php4", - "php5" - ] + "ext": ["php", "php3", "php4", "php5"] }, { "name": "PostScript source", "role": "Editor", - "ext": [ - "ps", - "eps" - ] + "ext": ["ps", "eps"] }, { "name": "Property list", "role": "Editor", - "ext": [ - "dict", - "plist", - "scriptSuite", - "scriptTerminology" - ] + "ext": ["dict", "plist", "scriptSuite", "scriptTerminology"] }, { "name": "Python source", "role": "Editor", - "ext": [ - "py", - "rpy", - "cpy", - "python" - ] + "ext": ["py", "rpy", "cpy", "python"] }, { "name": "R source", "role": "Editor", - "ext": [ - "r", - "s" - ] + "ext": ["r", "s"] }, { "name": "Ragel source", "role": "Editor", - "ext": [ - "rl", - "ragel" - ] + "ext": ["rl", "ragel"] }, { "name": "Remind document", "role": "Editor", - "ext": [ - "rem", - "remind" - ] + "ext": ["rem", "remind"] }, { "name": "reStructuredText document", "role": "Editor", - "ext": [ - "rst", - "rest" - ] + "ext": ["rst", "rest"] }, { "name": "HTML with embedded Ruby", "role": "Editor", - "ext": [ - "rhtml", - "erb" - ] + "ext": ["rhtml", "erb"] }, { "name": "SQL with embedded Ruby", @@ -567,28 +415,17 @@ { "name": "Ruby source", "role": "Editor", - "ext": [ - "rb", - "rbx", - "rjs", - "rxml" - ] + "ext": ["rb", "rbx", "rjs", "rxml"] }, { "name": "Sass source", "role": "Editor", - "ext": [ - "sass", - "scss" - ] + "ext": ["sass", "scss"] }, { "name": "Scheme source", "role": "Editor", - "ext": [ - "scm", - "sch" - ] + "ext": ["scm", "sch"] }, { "name": "Setext document", @@ -636,10 +473,7 @@ { "name": "SWIG source", "role": "Editor", - "ext": [ - "i", - "swg" - ] + "ext": ["i", "swg"] }, { "name": "Tcl source", @@ -649,20 +483,12 @@ { "name": "TeX document", "role": "Editor", - "ext": [ - "tex", - "sty", - "cls" - ] + "ext": ["tex", "sty", "cls"] }, { "name": "Plain text document", "role": "Editor", - "ext": [ - "text", - "txt", - "utf8" - ] + "ext": ["text", "txt", "utf8"] }, { "name": "Textile document", @@ -682,32 +508,17 @@ { "name": "XML document", "role": "Editor", - "ext": [ - "xml", - "xsd", - "xib", - "rss", - "tld", - "pt", - "cpt", - "dtml" - ] + "ext": ["xml", "xsd", "xib", "rss", "tld", "pt", "cpt", "dtml"] }, { "name": "XSL stylesheet", "role": "Editor", - "ext": [ - "xsl", - "xslt" - ] + "ext": ["xsl", "xslt"] }, { "name": "Electronic business card", "role": "Editor", - "ext": [ - "vcf", - "vcard" - ] + "ext": ["vcf", "vcard"] }, { "name": "Visual Basic source", @@ -717,10 +528,7 @@ { "name": "YAML document", "role": "Editor", - "ext": [ - "yaml", - "yml" - ] + "ext": ["yaml", "yml"] }, { "name": "Text document", @@ -782,67 +590,95 @@ "scripts": { "precommit": "pretty-quick --staged", "prepush": "npm run build && npm run lint", - "build": "npm run build:browser && npm run build:webview_preload && npm run build:main && npm run build:plugins", + "build": + "npm run build:browser && npm run build:webview_preload && npm run build:main && npm run build:plugins", "build-debug": "npm run build:browser-debug && npm run build:main && npm run build:plugins", "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": "npm run build:test:unit:browser && npm run build:test:unit:main", - "build:test:unit:browser": "rimraf lib_test/browser && cd browser && tsc -p tsconfig.test.json", + "build:test:unit:browser": + "rimraf lib_test/browser && cd browser && tsc -p tsconfig.test.json", "build:test:unit:main": "rimraf lib_test/main && cd main && tsc -p tsconfig.test.json", "build:webview_preload": "cd webview_preload && tsc -p tsconfig.json", "check-cached-binaries": "node build/script/CheckBinariesForBuild.js", "copy-icons": "node build/CopyIcons.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:screenshot": "npm run build:test && cross-env DEMO_TEST=HeroScreenshot mocha -t 30000000 lib_test/test/Demo.js", - "demo:video": "npm run build:test && cross-env DEMO_TEST=HeroDemo mocha -t 30000000 lib_test/test/Demo.js", - "dist:win:x86": "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=1 build --arch ia32 --publish never", - "dist:win:x64": "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=1 build --arch x64 --publish never", - "pack:win": "node build/BuildSetupTemplate.js && innosetup-compiler dist/setup.iss --verbose --O=dist", + "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:screenshot": + "npm run build:test && cross-env DEMO_TEST=HeroScreenshot mocha -t 30000000 lib_test/test/Demo.js", + "demo:video": + "npm run build:test && cross-env DEMO_TEST=HeroDemo mocha -t 30000000 lib_test/test/Demo.js", + "dist:win:x86": + "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=1 build --arch ia32 --publish never", + "dist:win:x64": + "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=1 build --arch x64 --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 --bail", "test:react": "jest --config ./jest.config.js ./ui-tests", "test:react:watch": "jest --config ./jest.config.js ./ui-tests --watch", "test:react:coverage": "jest --config ./jest.config.js ./ui-tests --coverage", - "test:unit:browser": "npm run build:test:unit:browser && cd browser && electron-mocha --renderer --require testHelpers.js --recursive ../lib_test/browser/test", + "test:unit:browser": + "npm run build:test:unit:browser && cd browser && electron-mocha --renderer --require testHelpers.js --recursive ../lib_test/browser/test", "test:unit": "npm run test:unit:browser && npm run test:unit:main && npm run test:react", - "test:unit:main": "npm run build:test:unit:main && cd main && electron-mocha --renderer --recursive ../lib_test/main/test", + "test:unit:main": + "npm run build:test:unit:main && cd main && electron-mocha --renderer --recursive ../lib_test/main/test", "upload:dist": "node build/script/UploadDistributionBuildsToAzure", "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": "cross-env ONI_CCOV=1 electron-mocha --renderer --require browser/testHelpers.js -R browser/testCoverageReporter --recursive lib_test/browser/test", - "ccov:remap:browser:html": "cd lib_test/browser/src && remap-istanbul --input ../../../coverage/coverage-final.json --output html-report --type html", - "ccov:remap:browser:lcov": "cd lib_test/browser/src && remap-istanbul --input ../../../coverage/coverage-final.json --output lcov.info --type lcovonly", + "ccov:instrument": + "nyc instrument --all true --sourceMap false lib_test/browser/src lib_test/browser/src_ccov", + "ccov:test:browser": + "cross-env ONI_CCOV=1 electron-mocha --renderer --require browser/testHelpers.js -R browser/testCoverageReporter --recursive lib_test/browser/test", + "ccov:remap:browser:html": + "cd lib_test/browser/src && remap-istanbul --input ../../../coverage/coverage-final.json --output html-report --type html", + "ccov:remap:browser:lcov": + "cd lib_test/browser/src && remap-istanbul --input ../../../coverage/coverage-final.json --output lcov.info --type lcovonly", "ccov:clean": "rimraf coverage", "ccov:upload": "codecov", "launch": "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": + "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.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: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", + "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 && npm run install:plugins:oni-plugin-prettier", - "install:plugins:oni-plugin-markdown-preview": "cd extensions/oni-plugin-markdown-preview && npm install --prod", - "install:plugins:oni-plugin-prettier": "cd extensions/oni-plugin-prettier && npm install --prod", + "install:plugins": + "npm run install:plugins:oni-plugin-markdown-preview && npm run install:plugins:oni-plugin-prettier", + "install:plugins:oni-plugin-markdown-preview": + "cd extensions/oni-plugin-markdown-preview && npm install --prod", + "install:plugins:oni-plugin-prettier": + "cd extensions/oni-plugin-prettier && 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", @@ -867,10 +703,11 @@ "react-dnd-html5-backend": "^2.5.4", "react-dom": "16.0.0", "redux-batched-subscribe": "^0.1.6", + "fs-extra": "^5.0.0", "shell-env": "^0.3.0", "shelljs": "0.7.7", "styled-components": "^2.3.0", - "typescript": "2.7.1", + "typescript": "^2.8.1", "vscode-css-languageserver-bin": "^1.2.1", "vscode-html-languageserver-bin": "^1.1.0", "vscode-jsonrpc": "3.5.0", @@ -879,6 +716,7 @@ "vscode-textmate": "3.2.0" }, "devDependencies": { + "@types/fs-extra": "^5.0.2", "@types/classnames": "0.0.32", "@types/color": "2.0.0", "@types/detect-indent": "^5.0.0", @@ -890,7 +728,6 @@ "@types/lodash": "4.14.38", "@types/lolex": "2.1.0", "@types/marked": "^0.3.0", - "@types/memory-fs": "^0.3.0", "@types/minimatch": "3.0.1", "@types/minimist": "1.1.29", "@types/mkdirp": "0.3.29", @@ -907,6 +744,7 @@ "@types/react-virtualized": "^9.7.10", "@types/redux-batched-subscribe": "^0.1.2", "@types/redux-mock-store": "^0.0.13", + "@types/rimraf": "^2.0.2", "@types/shelljs": "^0.7.7", "@types/sinon": "1.16.32", "autoprefixer": "6.4.0", @@ -931,7 +769,6 @@ "enzyme-to-json": "^3.3.1", "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", "husky": "^0.14.3", diff --git a/ui-tests/tsconfig.react.json b/ui-tests/tsconfig.react.json index f2d01cb791..b28da3b597 100644 --- a/ui-tests/tsconfig.react.json +++ b/ui-tests/tsconfig.react.json @@ -6,7 +6,7 @@ "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, "jsx": "react", - "lib": ["dom", "es2017"], + "lib": ["dom", "es2017", "ES2015"], "module": "commonjs", "moduleResolution": "node", "noEmitOnError": true, diff --git a/yarn.lock b/yarn.lock index f56b42324e..00840a2502 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,6 +93,12 @@ version "1.1.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-1.1.0.tgz#93b1be91f63c184450385272c47b6496fd028e02" +"@types/fs-extra@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.2.tgz#235a7e2b56452cc0a6a4809b53e1d1eaffff9c96" + dependencies: + "@types/node" "*" + "@types/glob@*": version "5.0.34" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.34.tgz#ee626c9be3da877d717911c6101eee0a9871bbf4" @@ -125,12 +131,6 @@ version "0.3.0" resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.3.0.tgz#583c223dd33385a1dda01aaf77b0cd0411c4b524" -"@types/memory-fs@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@types/memory-fs/-/memory-fs-0.3.0.tgz#847596a94f9a9688a2e342f4017fcc0050e8e2da" - dependencies: - "@types/node" "*" - "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -232,6 +232,13 @@ dependencies: redux "^3.6.0" +"@types/rimraf@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e" + dependencies: + "@types/glob" "*" + "@types/node" "*" + "@types/shelljs@^0.7.7": version "0.7.7" resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.7.tgz#1f7bfa28947661afea06365db9b1135bbc903ec4" @@ -4143,14 +4150,6 @@ fs-extra-p@^4.5.0, fs-extra-p@^4.5.2: bluebird-lst "^1.0.5" fs-extra "^5.0.0" -fs-extra@4.0.2, fs-extra@^4.0.1, fs-extra@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" @@ -4184,6 +4183,14 @@ fs-extra@^3.0.1: jsonfile "^3.0.0" universalify "^0.1.0" +fs-extra@^4.0.1, fs-extra@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" @@ -9862,9 +9869,9 @@ typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.1.tgz#bb3682c2c791ac90e7c6210b26478a8da085c359" +typescript@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624" ua-parser-js@^0.7.9: version "0.7.17" From d2942f05e9023ef9a8b842fb1e717c0aa51c8d17 Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Fri, 20 Apr 2018 08:02:25 +0100 Subject: [PATCH 45/59] Feature/filesystem watcher (#2116) * add FSWatcher initial implementation * add workspace default as dir to watch * add html loader banner plugin and aws to stop errors with node-pre-gyp * remove logs change event fns to prefix with on * Add ignore initial option to chokidar init * use ready event to initialise watcher * update chokidar and types in fswatcher * listen to workspace directory changes --- .../src/Services/Explorer/ExplorerSplit.tsx | 5 + .../src/Services/FileSystemWatcher/index.ts | 104 ++++++++++ browser/webpack.development.config.js | 7 + package.json | 4 + yarn.lock | 180 ++++++++++++++++-- 5 files changed, 287 insertions(+), 13 deletions(-) create mode 100644 browser/src/Services/FileSystemWatcher/index.ts diff --git a/browser/src/Services/Explorer/ExplorerSplit.tsx b/browser/src/Services/Explorer/ExplorerSplit.tsx index c471a3752c..fd52eb1176 100644 --- a/browser/src/Services/Explorer/ExplorerSplit.tsx +++ b/browser/src/Services/Explorer/ExplorerSplit.tsx @@ -7,6 +7,7 @@ import * as path from "path" import * as React from "react" import { Provider } from "react-redux" import { Store } from "redux" +import FileSystemWatcher from "./../../Services/FileSystemWatcher" import { Event } from "oni-types" @@ -58,6 +59,10 @@ export class ExplorerSplit { rootPath: this._workspace.activeWorkspace, }) } + + FileSystemWatcher.onChange.subscribe(() => this._store.dispatch({ type: "REFRESH" })) + FileSystemWatcher.onAdd.subscribe(() => this._store.dispatch({ type: "REFRESH" })) + FileSystemWatcher.onMove.subscribe(() => this._store.dispatch({ type: "REFRESH" })) } public enter(): void { diff --git a/browser/src/Services/FileSystemWatcher/index.ts b/browser/src/Services/FileSystemWatcher/index.ts new file mode 100644 index 0000000000..8885861cdc --- /dev/null +++ b/browser/src/Services/FileSystemWatcher/index.ts @@ -0,0 +1,104 @@ +import * as chokidar from "chokidar" +import { Stats } from "fs" +import { Event, IEvent } from "oni-types" + +import * as Workspace from "./../Workspace" + +export type Targets = string | string[] + +interface IFSOptions { + options?: chokidar.WatchOptions + target?: Targets +} + +interface IFileChangeEvent { + path: string +} + +interface IStatsChangeEvent { + path: string + stats: Stats +} + +export class FileSystemWatcher { + private _watcher: chokidar.FSWatcher + private _workspace: Workspace.Workspace + private _activeWorkspace: string + + private _onAdd = new Event<IFileChangeEvent>() + private _onAddDir = new Event<IStatsChangeEvent>() + private _onMove = new Event<IFileChangeEvent>() + private _onChange = new Event<IFileChangeEvent>() + private _defaultOptions = { ignored: "**/node_modules" } + + constructor(watch: IFSOptions = {}) { + this._workspace = Workspace.getInstance() + this._activeWorkspace = this._workspace.activeWorkspace + const fileOrFolder = watch.target || this._activeWorkspace + const optionsToUse = watch.options || this._defaultOptions + this._watcher = chokidar.watch(fileOrFolder, optionsToUse) + + // alternatively the ignoreInitial can be set in the config + // to avoid a flurry of events when the watcher is initialised + this._watcher.on("ready", () => { + this._attachEventListeners() + }) + + this._workspace.onDirectoryChanged.subscribe(newDirectory => { + this.unwatch(this._activeWorkspace) + this.watch(newDirectory) + }) + } + + public watch(target: Targets) { + return this._watcher.add(target) + } + + public unwatch(target: Targets) { + return this._watcher.unwatch(target) + } + + public close() { + this._watcher.close() + } + + private _attachEventListeners() { + this._watcher.on("add", path => { + return this._onAdd.dispatch(path) + }) + + this._watcher.on("change", path => { + return this._onChange.dispatch(path) + }) + + this._watcher.on("move", path => { + return this._onMove.dispatch(path) + }) + + this._watcher.on("addDir", (path, stats) => { + return this._onAddDir.dispatch({ path, stats }) + }) + } + + get allWatched(): chokidar.WatchedPaths { + return this._watcher.getWatched() + } + + get onChange(): IEvent<IFileChangeEvent> { + return this._onChange + } + + get onMove(): IEvent<IFileChangeEvent> { + return this._onMove + } + + get onAdd(): IEvent<IFileChangeEvent> { + return this._onAdd + } + + get addDir(): IEvent<IStatsChangeEvent> { + return this._onAddDir + } +} + +export default new FileSystemWatcher() diff --git a/browser/webpack.development.config.js b/browser/webpack.development.config.js index 201d4d2c0c..b026924ce7 100644 --- a/browser/webpack.development.config.js +++ b/browser/webpack.development.config.js @@ -13,12 +13,19 @@ module.exports = { gifshot: "require('gifshot')", "msgpack-lite": "require('msgpack-lite')", "styled-components": "require('styled-components')", + fsevents: "require('fsevents')", }, resolve: { extensions: [".tsx", ".ts", ".js", ".less"], }, module: { rules: [ + { + test: /\.(html)$/, + use: { + loader: "html-loader", + }, + }, { test: /\.less$/, use: [ diff --git a/package.json b/package.json index f7a1f7b82e..60fbdfacee 100644 --- a/package.json +++ b/package.json @@ -686,6 +686,7 @@ }, "license": "MIT", "dependencies": { + "chokidar": "^2.0.3", "dompurify": "^1.0.3", "electron-settings": "^3.1.4", "find-up": "2.1.0", @@ -716,6 +717,7 @@ "vscode-textmate": "3.2.0" }, "devDependencies": { + "@types/chokidar": "^1.7.5", "@types/fs-extra": "^5.0.2", "@types/classnames": "0.0.32", "@types/color": "2.0.0", @@ -748,6 +750,7 @@ "@types/shelljs": "^0.7.7", "@types/sinon": "1.16.32", "autoprefixer": "6.4.0", + "aws-sdk": "^2.202.0", "azure-storage": "^2.8.1", "babel-minify-webpack-plugin": "^0.3.1", "babel-plugin-dynamic-import-node": "^1.2.0", @@ -771,6 +774,7 @@ "find-process": "^1.1.0", "fuse.js": "2.6.2", "github-releases": "^0.4.1", + "html-loader": "^0.5.5", "husky": "^0.14.3", "innosetup-compiler": "5.5.9", "istanbul-api": "^1.2.1", diff --git a/yarn.lock b/yarn.lock index 00840a2502..f209486ddf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -48,6 +48,13 @@ version "0.22.7" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce" +"@types/chokidar@^1.7.5": + version "1.7.5" + resolved "https://registry.yarnpkg.com/@types/chokidar/-/chokidar-1.7.5.tgz#1fa78c8803e035bed6d98e6949e514b133b0c9b6" + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/classnames@0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-0.0.32.tgz#449abcd9a826807811ef101e58df9f83cfc61713" @@ -676,6 +683,10 @@ ast-types@0.11.3: version "0.11.3" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8" +ast-types@0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -736,6 +747,20 @@ autoprefixer@^6.0.0, autoprefixer@^6.3.1: postcss "^5.2.16" postcss-value-parser "^3.2.3" +aws-sdk@^2.202.0: + version "2.202.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.202.0.tgz#c1bd90c1dc0bfe835522fe81f29cf8bb71bf00cc" + dependencies: + buffer "4.9.1" + events "^1.1.1" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.1.0" + xml2js "0.4.17" + xmlbuilder "4.2.1" + aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" @@ -1841,6 +1866,10 @@ browserslist@~1.3.5: dependencies: caniuse-db "^1.0.30000525" +bs-platform@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-2.1.0.tgz#63560ff8f7142c9c0631559df1c35590b9f6d8b2" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -1863,7 +1892,7 @@ buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" -buffer@^4.3.0: +buffer@4.9.1, buffer@^4.3.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: @@ -1993,6 +2022,13 @@ callsites@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -2134,7 +2170,7 @@ chokidar@^1.6.0: optionalDependencies: fsevents "^1.0.0" -chokidar@^2.0.0, chokidar@^2.0.2: +chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" dependencies: @@ -2194,6 +2230,12 @@ 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" +clean-css@4.1.x: + version "4.1.9" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.9.tgz#35cee8ae7687a49b98034f70de00c4edd3826301" + dependencies: + source-map "0.5.x" + cli-boxes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" @@ -2398,6 +2440,10 @@ commander@2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" +commander@2.14.x, commander@~2.14.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" + commander@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d" @@ -3587,6 +3633,13 @@ es6-promise@^4.0.5: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a" +es6-templates@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/es6-templates/-/es6-templates-0.2.3.tgz#5cb9ac9fb1ded6eb1239342b81d792bbb4078ee4" + dependencies: + recast "~0.11.12" + through "~2.3.6" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -3628,7 +3681,7 @@ esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" -esprima@^3.1.3: +esprima@^3.1.3, esprima@~3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" @@ -3671,7 +3724,7 @@ eventemitter3@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" -events@^1.0.0: +events@^1.0.0, events@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -4683,7 +4736,7 @@ hawk@~6.0.2: hoek "4.x.x" sntp "2.x.x" -he@1.1.1: +he@1.1.1, he@1.1.x: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" @@ -4763,6 +4816,29 @@ html-entities@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" +html-loader@^0.5.5: + version "0.5.5" + resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-0.5.5.tgz#6356dbeb0c49756d8ebd5ca327f16ff06ab5faea" + dependencies: + es6-templates "^0.2.3" + fastparse "^1.1.1" + html-minifier "^3.5.8" + loader-utils "^1.1.0" + object-assign "^4.1.1" + +html-minifier@^3.5.8: + version "3.5.9" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.9.tgz#74424014b872598d4bb0e20ac420926ec61024b6" + dependencies: + camel-case "3.0.x" + clean-css "4.1.x" + commander "2.14.x" + he "1.1.x" + ncname "1.0.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.3.x" + htmlparser2@^3.9.1: version "3.9.2" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" @@ -5778,6 +5854,10 @@ jest@^22.2.2: import-local "^1.0.0" jest-cli "^22.3.0" +jmespath@0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + js-base64@^2.1.9: version "2.3.2" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf" @@ -6279,7 +6359,7 @@ lodash@4.17.0: version "4.17.0" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.0.tgz#93f4466e5ab73e5a1f1216c34eea11535f0a8df5" -lodash@4.17.5, lodash@^4.15.0, lodash@^4.17.5: +lodash@4.17.5, lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.5: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" @@ -6343,6 +6423,10 @@ loud-rejection@^1.0.0, loud-rejection@^1.6.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + lowercase-keys@1.0.0, lowercase-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" @@ -6778,6 +6862,12 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" +ncname@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c" + dependencies: + xml-char-classes "^1.0.0" + nearley@^2.7.10: version "2.11.1" resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.11.1.tgz#a9c0a5fa942998db5ad18b14fbc8e9fc49672f16" @@ -6799,6 +6889,12 @@ nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + dependencies: + lower-case "^1.1.1" + node-abi@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.2.tgz#4da6caceb6685fcd31e7dd1994ef6bb7d0a9c0b2" @@ -7393,6 +7489,12 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + dependencies: + no-case "^2.2.0" + parse-asn1@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" @@ -8346,6 +8448,15 @@ recast@^0.14.1: private "~0.1.5" source-map "~0.6.1" +recast@~0.11.12: + version "0.11.23" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + dependencies: + ast-types "0.9.6" + esprima "~3.1.0" + private "~0.1.5" + source-map "~0.5.0" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -8472,6 +8583,10 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + remap-istanbul@^0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/remap-istanbul/-/remap-istanbul-0.10.1.tgz#3aa58dd5021d499f336d3ba5bf3bbb91c1b88e37" @@ -8807,7 +8922,11 @@ sax@0.5.x: version "0.5.8" resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" -sax@^1.2.1, sax@^1.2.4, sax@~1.2.1: +sax@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + +sax@>=0.6.0, sax@^1.2.1, sax@^1.2.4, sax@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -9154,6 +9273,10 @@ source-map-url@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" +source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + source-map@^0.1.38: version "0.1.43" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" @@ -9166,10 +9289,6 @@ source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -9683,7 +9802,7 @@ through2@~0.2.3: readable-stream "~1.1.9" xtend "~2.1.1" -through@2, through@^2.3.6: +through@2, through@^2.3.6, through@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -9884,6 +10003,13 @@ uglify-es@^3.3.4: commander "~2.13.0" source-map "~0.6.1" +uglify-js@3.3.x: + version "3.3.12" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.12.tgz#efd87c16a1f4c674a8a5ede571001ef634dcc883" + dependencies: + commander "~2.14.1" + source-map "~0.6.1" + uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -10012,6 +10138,10 @@ update-notifier@^2.3.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + uri-js@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-3.0.2.tgz#f90b858507f81dea4dcfbb3c4c3dbfa2b557faaa" @@ -10056,6 +10186,13 @@ url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" +url@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + url@^0.11.0, url@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -10098,7 +10235,7 @@ utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" -uuid@^3.0.0, uuid@^3.1.0: +uuid@3.1.0, uuid@^3.0.0, uuid@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -10647,6 +10784,10 @@ xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" +xml-char-classes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" + xml-name-validator@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" @@ -10661,10 +10802,23 @@ xml2js@0.2.8: dependencies: sax "0.5.x" +xml2js@0.4.17: + version "0.4.17" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + dependencies: + sax ">=0.6.0" + xmlbuilder "^4.1.0" + xmlbuilder@0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.3.tgz#c4614ba74e0ad196e609c9272cd9e1ddb28a8a58" +xmlbuilder@4.2.1, xmlbuilder@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + dependencies: + lodash "^4.0.0" + xmlbuilder@8.2.2: version "8.2.2" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773" From a2b3dffacecdbe15220f3f2c0823c1233444bfd7 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Fri, 20 Apr 2018 17:20:48 -0700 Subject: [PATCH 46/59] Add Kaiden Sin as a backer - thank you! :) --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index 892f5a5d9d..e18de1ee31 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -108,6 +108,7 @@ Thanks you to all our backers for making Oni possible! * Clinton Bloodworth * Lex Song * Paul Baumgart +* Kaiden Sin <a href="https://opencollective.com/oni/tiers/backer/0/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/0/avatar.png"></a> <a href="https://opencollective.com/oni/tiers/backer/1/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/1/avatar.png"></a> From ea00e6cecc831d31314b93c30f1ea1a353133c55 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Fri, 20 Apr 2018 17:24:21 -0700 Subject: [PATCH 47/59] Add Troy Vitullo as a backer - thank you! :) --- .github/config.yml | 1 + BACKERS.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/config.yml b/.github/config.yml index 8ec6ad4a61..8975e058e3 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -28,3 +28,4 @@ backers: - 5697723 - 6803419 - 1718128 +- 2042893 diff --git a/BACKERS.md b/BACKERS.md index e18de1ee31..eda194cdaf 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -109,6 +109,7 @@ Thanks you to all our backers for making Oni possible! * Lex Song * Paul Baumgart * Kaiden Sin +* Troy Vitullo <a href="https://opencollective.com/oni/tiers/backer/0/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/0/avatar.png"></a> <a href="https://opencollective.com/oni/tiers/backer/1/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/1/avatar.png"></a> From 01b7ee03aa4c152a01de525df5becb6f302de661 Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Sat, 21 Apr 2018 09:20:08 +0100 Subject: [PATCH 48/59] bugfix/ add check to ensure there is an error event obj and it has a name (#2122) --- browser/src/Services/UnhandledErrorMonitor.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/browser/src/Services/UnhandledErrorMonitor.ts b/browser/src/Services/UnhandledErrorMonitor.ts index a19933cbff..6b00c530a7 100644 --- a/browser/src/Services/UnhandledErrorMonitor.ts +++ b/browser/src/Services/UnhandledErrorMonitor.ts @@ -38,7 +38,9 @@ export class UnhandledErrorMonitor { window.addEventListener("error", (evt: ErrorEvent) => { if (!this._started) { - const hasOccured = this._queuedErrors.find(e => e.name === evt.error.name) + const hasOccured = this._queuedErrors.find( + e => evt.error && e.name && e.name === evt.error.name, + ) if (!hasOccured) { this._queuedErrors.push(evt.error) } From 8c83855832a66165df09437c3c4a3ac767788860 Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Tue, 24 Apr 2018 07:02:19 +0100 Subject: [PATCH 49/59] Hotfix/fix fs event overload (#2124) * use ignore initial to prevent event bombardement * add throttled events * use audit time to throttle fs events in explorer * remove console.log * revert changes to fs watcher to avoid conflict with delete events pr --- browser/src/Services/Explorer/ExplorerStore.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/browser/src/Services/Explorer/ExplorerStore.ts b/browser/src/Services/Explorer/ExplorerStore.ts index 72c8cbc0bb..bcf9cf6145 100644 --- a/browser/src/Services/Explorer/ExplorerStore.ts +++ b/browser/src/Services/Explorer/ExplorerStore.ts @@ -633,13 +633,16 @@ export const clearUpdateEpic: ExplorerEpic = (action$, store) => .mergeMap(() => timer(2_000).mapTo(Actions.clearUpdate)) const refreshEpic: ExplorerEpic = (action$, store) => - action$.ofType("REFRESH").mergeMap(() => { - const state = store.getState() + action$ + .ofType("REFRESH") + .auditTime(300) + .mergeMap(() => { + const state = store.getState() - return Object.keys(state.expandedFolders).map(p => { - return Actions.expandDirectory(p) + return Object.keys(state.expandedFolders).map(p => { + return Actions.expandDirectory(p) + }) }) - }) const expandDirectoryEpic: ExplorerEpic = (action$, store, { fileSystem }) => action$.ofType("EXPAND_DIRECTORY").flatMap(async (action: ExplorerAction) => { From 96c5b27c6abddabdb9800c954164b2ce3a8250e1 Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Tue, 24 Apr 2018 07:03:57 +0100 Subject: [PATCH 50/59] Feature/ add delete event so watcher picks up all deletions (#2121) * add delete event so watcher picks up deletions properly add check to see if project root is different before triggering change dir * remove references to workspace from the fswatcher into explorer * add delete dir event and rename addDir to onAddDir --- .../src/Services/Explorer/ExplorerSplit.tsx | 17 ++++++-- .../src/Services/FileSystemWatcher/index.ts | 42 +++++++++---------- browser/src/Services/Workspace/Workspace.ts | 4 +- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/browser/src/Services/Explorer/ExplorerSplit.tsx b/browser/src/Services/Explorer/ExplorerSplit.tsx index fd52eb1176..d4288e83d1 100644 --- a/browser/src/Services/Explorer/ExplorerSplit.tsx +++ b/browser/src/Services/Explorer/ExplorerSplit.tsx @@ -7,7 +7,7 @@ import * as path from "path" import * as React from "react" import { Provider } from "react-redux" import { Store } from "redux" -import FileSystemWatcher from "./../../Services/FileSystemWatcher" +import { FileSystemWatcher } from "./../../Services/FileSystemWatcher" import { Event } from "oni-types" @@ -46,11 +46,19 @@ export class ExplorerSplit { ) { this._store = createStore({ notifications: NotificationsInstance() }) + const Watcher = new FileSystemWatcher({ + target: this._workspace.activeWorkspace, + options: { ignoreInitial: true, ignored: "**/node_modules" }, + }) + this._workspace.onDirectoryChanged.subscribe(newDirectory => { this._store.dispatch({ type: "SET_ROOT_DIRECTORY", rootPath: newDirectory, }) + + Watcher.unwatch(this._workspace.activeWorkspace) + Watcher.watch(newDirectory) }) if (this._workspace.activeWorkspace) { @@ -60,9 +68,10 @@ export class ExplorerSplit { }) } - FileSystemWatcher.onChange.subscribe(() => this._store.dispatch({ type: "REFRESH" })) - FileSystemWatcher.onAdd.subscribe(() => this._store.dispatch({ type: "REFRESH" })) - FileSystemWatcher.onMove.subscribe(() => this._store.dispatch({ type: "REFRESH" })) + const events = ["onChange", "onAdd", "onAddDir", "onMove", "onDelete", "onDeleteDir"] + events.forEach(event => + Watcher[event].subscribe(() => this._store.dispatch({ type: "REFRESH" })), + ) } public enter(): void { diff --git a/browser/src/Services/FileSystemWatcher/index.ts b/browser/src/Services/FileSystemWatcher/index.ts index 8885861cdc..fdf2a5fcb2 100644 --- a/browser/src/Services/FileSystemWatcher/index.ts +++ b/browser/src/Services/FileSystemWatcher/index.ts @@ -2,8 +2,6 @@ import * as chokidar from "chokidar" import { Stats } from "fs" import { Event, IEvent } from "oni-types" -import * as Workspace from "./../Workspace" - export type Targets = string | string[] interface IFSOptions { @@ -22,32 +20,20 @@ interface IStatsChangeEvent { export class FileSystemWatcher { private _watcher: chokidar.FSWatcher - private _workspace: Workspace.Workspace - private _activeWorkspace: string private _onAdd = new Event<IFileChangeEvent>() private _onAddDir = new Event<IStatsChangeEvent>() + private _onDelete = new Event<IFileChangeEvent>() + private _onDeleteDir = new Event<IFileChangeEvent>() private _onMove = new Event<IFileChangeEvent>() private _onChange = new Event<IFileChangeEvent>() - private _defaultOptions = { ignored: "**/node_modules" } - constructor(watch: IFSOptions = {}) { - this._workspace = Workspace.getInstance() - this._activeWorkspace = this._workspace.activeWorkspace - const fileOrFolder = watch.target || this._activeWorkspace - const optionsToUse = watch.options || this._defaultOptions - this._watcher = chokidar.watch(fileOrFolder, optionsToUse) + constructor({ target, options }: IFSOptions) { + this._watcher = chokidar.watch(target, options) - // alternatively the ignoreInitial can be set in the config - // to avoid a flurry of events when the watcher is initialised this._watcher.on("ready", () => { this._attachEventListeners() }) - - this._workspace.onDirectoryChanged.subscribe(newDirectory => { - this.unwatch(this._activeWorkspace) - this.watch(newDirectory) - }) } public watch(target: Targets) { @@ -75,6 +61,14 @@ export class FileSystemWatcher { return this._onMove.dispatch(path) }) + this._watcher.on("unlink", path => { + return this._onDelete.dispatch(path) + }) + + this._watcher.on("unlinkDir", path => { + return this._onDeleteDir.dispatch(path) + }) + this._watcher.on("addDir", (path, stats) => { return this._onAddDir.dispatch({ path, stats }) }) @@ -88,6 +82,14 @@ export class FileSystemWatcher { return this._onChange } + get onDelete(): IEvent<IFileChangeEvent> { + return this._onDelete + } + + get onDeleteDir(): IEvent<IFileChangeEvent> { + return this._onDeleteDir + } + get onMove(): IEvent<IFileChangeEvent> { return this._onMove } @@ -96,9 +98,7 @@ export class FileSystemWatcher { return this._onAdd } - get addDir(): IEvent<IStatsChangeEvent> { + get onAddDir(): IEvent<IFileChangeEvent> { return this._onAddDir } } - -export default new FileSystemWatcher() diff --git a/browser/src/Services/Workspace/Workspace.ts b/browser/src/Services/Workspace/Workspace.ts index 4b72ec599b..2d42148a9a 100644 --- a/browser/src/Services/Workspace/Workspace.ts +++ b/browser/src/Services/Workspace/Workspace.ts @@ -138,8 +138,8 @@ export class Workspace implements IWorkspace { const filePath = await findup(projectMarkers, { cwd }) if (filePath) { - const dir = path.dirname(filePath) - this.changeDirectory(dir) + const projectRoot = path.dirname(filePath) + return projectRoot !== this._activeWorkspace ? this.changeDirectory(projectRoot) : null } } From 7fc14d050cac9acd87dbe837473a8c9704f0bf07 Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Tue, 24 Apr 2018 07:05:04 +0100 Subject: [PATCH 51/59] Feature/add rename file functionality (#2115) * add yank and paste functionality [WIP] * add yank paste commands and reducer to the store * add initial working yank and paste command functionality * allow yanks to be stored as array for multiselecting * add timeout to remove yanked items after a minute idle add leave handler to reset yank and paste register allow toggle functionality if item already yanked * add h and l to expand and collapse dirs * add initial undo register and hopeless transitions * [WIP] add initial working..not fully tested undo functionality * move logic out of split into epics - for undo funcitionality also add guards if none present and remove an undo if successful from the register * add is focused to sidebar type * expose is focused method and check for it before applying bindings * add initial tests for yank epic * add epic test [wip] * remove types for memory fs since it needs to be required? * remove unsused vars * remove paste folder in test * add delete undo functionality add new methods to filesystem to have it control the shell commands * fix lint error * fix config typing typo * add true delete command and associated function rename methods of filesystem * fix broken utility function * add tests for Explorer file system * fix failing test * add coverage output directory * update tests - add move collection add is ci utility * commit utility file * fix changed typing to moveNodes function * add tests for small utilities * rename persist file function * switch to use of path.join in moving * finalise animation and tidy up epics * add reducer tests, use lodash utilities not homegrown * fix tests [WIP] fix epic typing for delete * fix notification message * fix delete epic and map to refresh * inject promisify as well as fs into oni file system * fix type errors * inject promisify and [wip] mock in jest test * refactor move logic out of split into filesystem add epic for pasting * fix undo functionality * refactor some method names for readablility * consolidate actions for typing and reuse * delegate error handling to epic catch clauses for greater flexibility as this gives back access to the observable so potentially a retry could be attempted or map to another action etc. * refactor notifications into epics fix jest test * add error notification with reason * consolidate replicated code into a function * set failures to warning level * fix tests.ts and ad log to paste * add get source node method to use to ensure undo causes expansion * move jest test to unit tests dir :sad: * add passing paste epic test * rename explorer filestystem tests * move fs-extra to deps add moar tests * add undo epic tests * add test for deletion in undo epic * remove redundant function and replace with fs-extra fn * add clear update functionality to prevent re-animating * add test for clear update epics * gate bindings not to apply if commandline or menu are open * fix paste action error handling * fix tests by ensuring mocks are async * import specific helpers from rxjs not all of observable fix tests simplify updating * add initial implementation of rename * add rename toggle functionality make input element a styled component * add rename epic and undo * add rename functionality and toggle commands to respect isRenaming * add initial rename and undo rename functionality * add tweaks for brevity in rename functionality * add rename success notification * shorten notification names add tests * add initial enzyme test for explorer nodeview * add enzyme test for nodeview * add snapshot for nodeview * add electron run as node pre jest tests * add notification tests remove run as node flag * add mock for keyboard layout class --- browser/src/Input/KeyBindings.ts | 1 + .../src/Services/Explorer/ExplorerSplit.tsx | 67 ++++- .../src/Services/Explorer/ExplorerStore.ts | 234 +++++++++++++++--- .../src/Services/Explorer/ExplorerView.tsx | 43 +++- browser/src/UI/components/LightweightText.tsx | 34 ++- .../Services/Explorer/ExplorerStoreTests.ts | 118 ++++++++- jest.config.js | 1 + package.json | 4 +- ui-tests/NodeView.test.tsx | 69 ++++++ ui-tests/__snapshots__/NodeView.test.tsx.snap | 35 +++ ui-tests/mocks/Utility.ts | 1 + ui-tests/mocks/keyboardLayout.ts | 14 ++ yarn.lock | 2 +- 13 files changed, 558 insertions(+), 65 deletions(-) create mode 100644 ui-tests/NodeView.test.tsx create mode 100644 ui-tests/__snapshots__/NodeView.test.tsx.snap create mode 100644 ui-tests/mocks/keyboardLayout.ts diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index 93efe00ae3..efdb8e6aac 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -141,6 +141,7 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind("u", "explorer.undo", isExplorerActive) input.bind("h", "explorer.collapse.directory", isExplorerActive) input.bind("l", "explorer.expand.directory", isExplorerActive) + input.bind("r", "explorer.rename", isExplorerActive) // Browser input.bind("k", "browser.scrollUp") diff --git a/browser/src/Services/Explorer/ExplorerSplit.tsx b/browser/src/Services/Explorer/ExplorerSplit.tsx index d4288e83d1..c6939aa398 100644 --- a/browser/src/Services/Explorer/ExplorerSplit.tsx +++ b/browser/src/Services/Explorer/ExplorerSplit.tsx @@ -86,13 +86,14 @@ export class ExplorerSplit { public moveFileOrFolder = (source: Node, dest: Node): void => { this._store.dispatch({ type: "PASTE", pasted: [source], target: dest }) - this._store.dispatch({ type: "REFRESH" }) } public render(): JSX.Element { return ( <Provider store={this._store}> <Explorer + onCompleteRename={this._completeRename} + onCancelRename={this._cancelRename} onSelectionChanged={id => this._onSelectionChanged(id)} onClick={id => this._onOpenItem(id)} moveFileOrFolder={this.moveFileOrFolder} @@ -101,15 +102,26 @@ export class ExplorerSplit { ) } + private _isRenaming = () => { + const { register: { rename } } = this._store.getState() + return rename.active + } + private _initialiseExplorerCommands(): void { this._commandManager.registerCommand( - new CallbackCommand("explorer.delete.persist", null, null, () => - this._onDeleteItem({ persist: true }), + new CallbackCommand( + "explorer.delete.persist", + null, + null, + () => !this._isRenaming() && this._onDeleteItem({ persist: true }), ), ) this._commandManager.registerCommand( - new CallbackCommand("explorer.delete", null, null, () => - this._onDeleteItem({ persist: false }), + new CallbackCommand( + "explorer.delete", + null, + null, + () => !this._isRenaming() && this._onDeleteItem({ persist: false }), ), ) this._commandManager.registerCommand( @@ -117,13 +129,16 @@ export class ExplorerSplit { "explorer.yank", "Yank Selected Item", "Select a file to move", - () => this._onYankItem(), + () => !this._isRenaming() && this._onYankItem(), ), ) this._commandManager.registerCommand( - new CallbackCommand("explorer.undo", "Undo last explorer action", null, () => - this._onUndoItem(), + new CallbackCommand( + "explorer.undo", + "Undo last explorer action", + null, + () => !this._isRenaming() && this._onUndoItem(), ), ) @@ -132,7 +147,7 @@ export class ExplorerSplit { "explorer.paste", "Move/Paste Selected Item", "Paste the last yanked item", - () => this._onPasteItem(), + () => !this._isRenaming() && this._onPasteItem(), ), ) @@ -141,7 +156,7 @@ export class ExplorerSplit { "explorer.expand.directory", "Expand a selected directory", null, - () => this._toggleDirectory("expand"), + () => !this._isRenaming() && this._toggleDirectory("expand"), ), ) @@ -150,7 +165,16 @@ export class ExplorerSplit { "explorer.collapse.directory", "Collapse selected directory", null, - () => this._toggleDirectory("collapse"), + () => !this._isRenaming() && this._toggleDirectory("collapse"), + ), + ) + + this._commandManager.registerCommand( + new CallbackCommand( + "explorer.rename", + "Rename the selected file/folder", + null, + () => !this._isRenaming() && this._renameItem(), ), ) } @@ -218,6 +242,27 @@ export class ExplorerSplit { return parentNode } + private _renameItem = () => { + const selected = this._getSelectedItem() + if (!selected) { + return + } + this._store.dispatch({ type: "RENAME_START", target: selected }) + } + + private _completeRename = (newName: string) => { + const target = this._getSelectedItem() + + if (!target) { + return + } + this._store.dispatch({ type: "RENAME_COMMIT", newName, target }) + } + + private _cancelRename = () => { + this._store.dispatch({ type: "RENAME_CANCEL" }) + } + // This is different from on openItem since it only activates if the target is a folder // also it means that each bound key only does one thing aka "h" collapses and "l" // expands they are not toggles diff --git a/browser/src/Services/Explorer/ExplorerStore.ts b/browser/src/Services/Explorer/ExplorerStore.ts index bcf9cf6145..deb78bf340 100644 --- a/browser/src/Services/Explorer/ExplorerStore.ts +++ b/browser/src/Services/Explorer/ExplorerStore.ts @@ -41,6 +41,10 @@ export const DefaultRegisterState: IRegisterState = { undo: [], paste: EmptyNode, updated: null, + rename: { + active: false, + target: null, + }, } export interface IFileState { @@ -71,11 +75,17 @@ export type RegisterAction = | IUndoAction | IUndoSuccessAction | IUndoFailAction + | IRenameSuccessAction + | IRenameFailAction interface IRegisterState { yank: ExplorerNode[] paste: ExplorerNode undo: RegisterAction[] + rename: { + active: boolean + target: ExplorerNode + } updated: string[] } @@ -191,6 +201,39 @@ export interface IPasteSuccessAction { moved: IMovedNodes[] } +export interface IRenameStartAction { + type: "RENAME_START" + target: ExplorerNode + active: boolean +} + +export interface IRenameSuccessAction { + type: "RENAME_SUCCESS" + source: string + destination: string + targetType: string +} + +export interface IRenameFailAction { + type: "RENAME_FAIL" + reason: string +} + +export interface ICancelRenameAction { + type: "RENAME_CANCEL" +} + +export interface IRenameCommitAction { + type: "RENAME_COMMIT" + target: ExplorerNode + newName: string +} + +export interface INotificationSentAction { + type: "NOTIFICATION_SENT" + typeOfNotification: string +} + export interface IMovedNodes { node: ExplorerNode destination: string @@ -203,6 +246,11 @@ export type ExplorerAction = | ICollapseDirectory | ISetRootDirectoryAction | IExpandDirectoryAction + | IRenameStartAction + | IRenameSuccessAction + | IRenameFailAction + | IRenameCommitAction + | ICancelRenameAction | IDeleteFailAction | IRefreshAction | IDeleteAction @@ -216,6 +264,7 @@ export type ExplorerAction = | IUndoAction | IUndoSuccessAction | IUndoFailAction + | INotificationSentAction // Helper functions for Updating state ======================================================== export const removePastedNode = (nodeArray: ExplorerNode[], ids: string[]): ExplorerNode[] => @@ -234,7 +283,11 @@ const getSourceAndDestPaths = (source: ExplorerNode, dest: ExplorerNode) => { // Do not add un-undoable action to the undo list export const shouldAddDeletion = (action: IDeleteSuccessAction) => (action.persist ? [action] : []) -type Updates = IPasteSuccessAction | IDeleteSuccessAction | IUndoSuccessAction +type Updates = + | IPasteSuccessAction + | IDeleteSuccessAction + | IUndoSuccessAction + | IRenameSuccessAction export const getUpdatedNode = (action: Updates, state?: IRegisterState): string[] => { switch (action.type) { @@ -242,6 +295,8 @@ export const getUpdatedNode = (action: Updates, state?: IRegisterState): string[ return action.moved.map(node => node.destination) case "DELETE_SUCCESS": return [getPathForNode(action.target)] + case "RENAME_SUCCESS": + return [action.destination] case "UNDO_SUCCESS": const lastAction = last(state.undo) @@ -249,6 +304,8 @@ export const getUpdatedNode = (action: Updates, state?: IRegisterState): string[ return [getPathForNode(lastAction.target)] } else if (lastAction.type === "PASTE") { return lastAction.pasted.map(node => getPathForNode(node)) + } else if (lastAction.type === "RENAME_SUCCESS") { + return [lastAction.source] } return [] @@ -263,7 +320,9 @@ const shouldExpandDirectory = (targets: ExplorerNode[]): IExpandDirectoryAction[ .filter(Boolean) export const getPathForNode = (node: ExplorerNode) => { - if (node.type === "file") { + if (!node) { + return null + } else if (node.type === "file") { return node.filePath } else if (node.type === "folder") { return node.folderPath @@ -286,6 +345,18 @@ const Actions = { undoSuccess: { type: "UNDO_SUCCESS" } as IUndoSuccessAction, + renameSuccess: ({ + source, + destination, + targetType, + }: { + source: string + destination: string + targetType: string + }) => ({ type: "RENAME_SUCCESS", destination, source, targetType } as IRenameSuccessAction), + + renameFail: (reason: string) => ({ type: "RENAME_FAIL", reason } as IRenameFailAction), + paste: { type: "PASTE" } as IPasteAction, refresh: { type: "REFRESH" } as IRefreshAction, @@ -302,6 +373,11 @@ const Actions = { persist, }), + notificationSent: (typeOfNotification: string): INotificationSentAction => ({ + type: "NOTIFICATION_SENT", + typeOfNotification, + }), + expandDirectory: (directoryPath: string): IExpandDirectoryAction => ({ type: "EXPAND_DIRECTORY", directoryPath, @@ -333,6 +409,32 @@ export const yankRegisterReducer: Reducer<IRegisterState> = ( action: ExplorerAction, ) => { switch (action.type) { + case "RENAME_START": + return { + ...state, + rename: { + active: true, + target: action.target, + }, + } + case "RENAME_CANCEL": + return { + ...state, + rename: { + active: false, + target: null, + }, + } + case "RENAME_SUCCESS": + return { + ...state, + undo: [...state.undo, action], + updated: getUpdatedNode(action), + rename: { + active: false, + target: null, + }, + } case "YANK": return { ...state, @@ -507,7 +609,28 @@ const deletionNotification = ({ type, name, notifications }: SendNotificationArg sendExplorerNotification( { title: `${capitalize(type)} deleted`, - details: `${name} was deleted successfully`, + details: `${path.basename(name)} was deleted successfully`, + }, + notifications, + ) + +interface RenameNotificationArgs { + type: string + source: string + destination: string + notifications: Notifications +} + +const renameNotification = ({ + notifications, + type, + source, + destination, +}: RenameNotificationArgs): void => + sendExplorerNotification( + { + title: `${capitalize(type)} renamed successfully`, + details: `${path.basename(source)} renamed to ${path.basename(destination)}`, }, notifications, ) @@ -594,6 +717,15 @@ export const undoEpic: ExplorerEpic = (action$, store, { fileSystem }) => return [Actions.undoFail("The last deletion cannot be undone, sorry")] }) : [Actions.undoFail("The last deletion cannot be undone, sorry")] + + case "RENAME_SUCCESS": + const { source, destination } = lastAction + return fromPromise(fileSystem.move(destination, source)) + .flatMap(() => successActions([])) + .catch(error => { + Log.warn(error) + return [Actions.undoFail("The last rename could not be undone, sorry")] + }) default: return [Actions.undoFail("Sorry we can't undo the last action")] } @@ -621,6 +753,21 @@ export const deleteEpic: ExplorerEpic = (action$, store, { fileSystem }) => ) }) +export const renameEpic: ExplorerEpic = (action$, store, { fileSystem }) => + action$.ofType("RENAME_COMMIT").mergeMap(({ newName, target }: IRenameCommitAction) => { + const source = getPathForNode(target) + const destination = path.join(path.dirname(source), newName) + return fromPromise(fileSystem.move(source, destination)) + .flatMap(() => [ + Actions.renameSuccess({ source, destination, targetType: target.type }), + Actions.refresh, + ]) + .catch(error => { + Log.warn(error) + return [Actions.renameFail(error.message)] + }) + }) + export const clearYankRegisterEpic: ExplorerEpic = (action$, store) => action$.ofType("YANK").mergeMap((action: IYankAction) => { const oneMinute = 60_000 @@ -660,38 +807,56 @@ const expandDirectoryEpic: ExplorerEpic = (action$, store, { fileSystem }) => }) export const notificationEpic: ExplorerEpic = (action$, store, { notifications }) => - action$.ofType("PASTE_SUCCESS", "DELETE_SUCCESS", "PASTE_FAIL", "DELETE_FAIL").map(action => { - switch (action.type) { - case "PASTE_SUCCESS": - action.moved.map(item => - moveNotification({ + action$ + .ofType( + "PASTE_SUCCESS", + "DELETE_SUCCESS", + "RENAME_SUCCESS", + "RENAME_FAIL", + "PASTE_FAIL", + "DELETE_FAIL", + ) + .map(action => { + switch (action.type) { + case "PASTE_SUCCESS": + action.moved.map(item => + moveNotification({ + notifications, + type: item.node.type, + name: item.node.name, + destination: item.destination, + }), + ) + return Actions.notificationSent(action.type) + case "DELETE_SUCCESS": + deletionNotification({ notifications, - type: item.node.type, - name: item.node.name, - destination: item.destination, - }), - ) - return Actions.Null - case "DELETE_SUCCESS": - deletionNotification({ - notifications, - type: action.target.type, - name: action.target.name, - }) - return Actions.Null - case "PASTE_FAIL": - case "DELETE_FAIL": - const [type] = action.type.split("_") - errorNotification({ - type, - notifications, - reason: action.reason, - }) - return Actions.Null - default: - return Actions.Null - } - }) + type: action.target.type, + name: action.target.name, + }) + return Actions.notificationSent(action.type) + case "RENAME_SUCCESS": + renameNotification({ + notifications, + type: action.targetType, + source: action.source, + destination: action.destination, + }) + return Actions.notificationSent(action.type) + case "PASTE_FAIL": + case "DELETE_FAIL": + case "RENAME_FAIL": + const [type] = action.type.split("_") + errorNotification({ + type, + notifications, + reason: action.reason, + }) + return Actions.notificationSent(action.type) + default: + return Actions.Null + } + }) interface ICreateStore { fileSystem?: IFileSystem @@ -709,6 +874,7 @@ export const createStore = ({ setRootDirectoryEpic, clearUpdateEpic, clearYankRegisterEpic, + renameEpic, pasteEpic, undoEpic, deleteEpic, diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index 949fac7ba0..747b492e53 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -11,7 +11,8 @@ import { compose } from "redux" import { CSSTransition, TransitionGroup } from "react-transition-group" -import { styled } from "./../../UI/components/common" +import { css, styled } from "./../../UI/components/common" +import { TextInputView } from "./../../UI/components/LightweightText" import { SidebarContainerView, SidebarItemView } from "./../../UI/components/SidebarItemView" import { Sneakable } from "./../../UI/components/Sneakable" import { VimNavigator } from "./../../UI/components/VimNavigator" @@ -29,11 +30,14 @@ export interface INodeViewProps { node: ExplorerSelectors.ExplorerNode isSelected: boolean onClick: () => void + onCancelRename: () => void + onCompleteRename: (newName: string) => void yanked: string[] updated?: string[] + isRenaming: Node } -const NodeWrapper = styled.div` +export const NodeWrapper = styled.div` &:hover { text-decoration: underline; } @@ -93,6 +97,17 @@ const Transition = ({ children, updated }: ITransitionProps) => ( </CSSTransition> ) +const renameStyles = css` + width: 100%; + background-color: inherit; + color: inherit; + font-size: inherit; + font-family: inherit; + padding: 0.5rem; + box-sizing: border-box; + border: 2px solid ${p => p.theme["highlight.mode.normal.background"]} !important; +` + export class NodeView extends React.PureComponent<INodeViewProps, {}> { public moveFileOrFolder = ({ drag, drop }: IMoveNode) => { this.props.moveFileOrFolder(drag.node, drop.node) @@ -103,12 +118,22 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { } public render(): JSX.Element { + const { isRenaming, isSelected, node } = this.props + const renameInProgress = isRenaming.name === node.name && isSelected return ( <NodeWrapper style={{ cursor: "pointer" }} innerRef={this.props.isSelected ? scrollIntoViewIfNeeded : noop} > - {this.getElement()} + {renameInProgress ? ( + <TextInputView + styles={renameStyles} + onCancel={this.props.onCancelRename} + onComplete={this.props.onCompleteRename} + /> + ) : ( + this.getElement() + )} </NodeWrapper> ) } @@ -211,7 +236,10 @@ export interface IExplorerViewContainerProps { moveFileOrFolder: (source: Node, dest: Node) => void onSelectionChanged: (id: string) => void onClick: (id: string) => void + onCancelRename: () => void + onCompleteRename: (newName: string) => void yanked?: string[] + isRenaming?: Node } export interface IExplorerViewProps extends IExplorerViewContainerProps { @@ -243,13 +271,16 @@ export class ExplorerView extends React.PureComponent<IExplorerViewProps, {}> { <TransitionGroup> <VimNavigator ids={ids} - active={this.props.isActive} + active={this.props.isActive && !this.props.isRenaming} onSelectionChanged={this.props.onSelectionChanged} onSelected={id => this.props.onClick(id)} render={(selectedId: string) => { const nodes = this.props.nodes.map(node => ( <Sneakable callback={() => this.props.onClick(node.id)} key={node.id}> <NodeView + onCompleteRename={this.props.onCompleteRename} + isRenaming={this.props.isRenaming} + onCancelRename={this.props.onCancelRename} updated={this.props.updated} yanked={this.props.yanked} moveFileOrFolder={this.props.moveFileOrFolder} @@ -277,12 +308,14 @@ const mapStateToProps = ( containerProps: IExplorerViewContainerProps, ): IExplorerViewProps => { const yanked = state.register.yank.map(node => node.id) + const { register: { updated, rename } } = state return { ...containerProps, isActive: state.hasFocus, nodes: ExplorerSelectors.mapStateToNodeList(state), - updated: state.register.updated, + updated, yanked, + isRenaming: rename.active && rename.target, } } diff --git a/browser/src/UI/components/LightweightText.tsx b/browser/src/UI/components/LightweightText.tsx index 7aff1e7a6c..eb0b2cf496 100644 --- a/browser/src/UI/components/LightweightText.tsx +++ b/browser/src/UI/components/LightweightText.tsx @@ -1,15 +1,28 @@ import * as React from "react" import { focusManager } from "./../../Services/FocusManager" +import { styled, withProps } from "./../components/common" export interface ITextInputViewProps { onCancel?: () => void onComplete?: (result: string) => void onChange?: (evt: React.ChangeEvent<HTMLInputElement>) => void + styles?: any defaultValue?: string } +export interface IInputProps extends ITextInputViewProps { + inputStyles?: any + onKeyDown: (evt: React.KeyboardEvent<HTMLInputElement>) => void + onChange: (evt: React.ChangeEvent<HTMLInputElement>) => void + onFocus: (evt: React.FocusEvent<HTMLInputElement>) => void +} + +const Input = withProps<IInputProps>(styled.input)` + ${p => p.inputStyles}; +` + // TODO: Is there a better value for this? const WordRegex = /[$_a-zA-Z0-9]/i @@ -37,16 +50,17 @@ export class TextInputView extends React.PureComponent<ITextInputViewProps, {}> return ( <div className="input-container enable-mouse"> - <input + <Input type="text" + inputStyles={this.props.styles} style={inputStyle} placeholder={defaultValue} - onKeyDown={evt => this._onKeyDown(evt)} - onChange={evt => this._onChange(evt)} - onFocus={evt => evt.currentTarget.select()} - ref={elem => { - this._element = elem - }} + onKeyDown={this._onKeyDown} + onChange={this._onChange} + onFocus={(evt: React.FocusEvent<HTMLInputElement>) => + evt.currentTarget.select() + } + innerRef={(elem: HTMLInputElement) => (this._element = elem)} /> </div> ) @@ -59,19 +73,19 @@ export class TextInputView extends React.PureComponent<ITextInputViewProps, {}> } } - private _onChange(changeEvent: React.ChangeEvent<HTMLInputElement>): void { + private _onChange = (changeEvent: React.ChangeEvent<HTMLInputElement>): void => { if (this.props.onChange) { this.props.onChange(changeEvent) } } - private _cancel(): void { + private _cancel = (): void => { if (this.props.onCancel) { this.props.onCancel() } } - private _onKeyDown(keyboardEvent: React.KeyboardEvent<HTMLInputElement>): void { + private _onKeyDown = (keyboardEvent: React.KeyboardEvent<HTMLInputElement>): void => { if (keyboardEvent.keyCode === 27) { this._cancel() return diff --git a/browser/test/Services/Explorer/ExplorerStoreTests.ts b/browser/test/Services/Explorer/ExplorerStoreTests.ts index 46885ba3fe..196efb0658 100644 --- a/browser/test/Services/Explorer/ExplorerStoreTests.ts +++ b/browser/test/Services/Explorer/ExplorerStoreTests.ts @@ -55,7 +55,10 @@ export class MockedFileSystem implements ExplorerFileSystem.IFileSystem { const rootEpic = combineEpics(ExplorerState.clearYankRegisterEpic, ExplorerState.pasteEpic) const epicMiddleware = createEpicMiddleware(rootEpic, { - dependencies: { fileSystem: MockedFileSystem as any, notifications: {} as Notifications }, + dependencies: { + fileSystem: MockedFileSystem as any, + notifications: {} as Notifications, + }, }) const MemoryFileSystem = require("memory-fs") // tslint:disable-line @@ -157,7 +160,20 @@ describe("ExplorerStore", () => { moveNodesBack: async collection => null, } as ExplorerFileSystem.IFileSystem - const notifications = {} as Notifications + const notifications = { + _id: 0, + _overlay: null, + _overlayManager: null, + _store: null, + enable: true, + disable: false, + createItem: () => ({ + setContents: (title: string, details: string) => ({ title, details }), + setLevel: (level: string) => ({ level }), + setExpiration: (expirationTime: number) => ({ expirationTime: 8_000 }), + show: () => ({}), + }), + } as any it("dispatches a clear register action after a minute", async () => { epicStore.dispatch({ type: "YANK", target }) @@ -371,6 +387,80 @@ describe("ExplorerStore", () => { assert.deepEqual(actualActions, expected) }) }) + + it("Should move an item when a rename is triggered", () => { + const action$ = ActionsObservable.of({ + type: "RENAME_COMMIT", + target: target1, + newName: "testing", + } as ExplorerState.IRenameCommitAction) + + const expected = [ + { + type: "RENAME_SUCCESS", + targetType: "folder", + source: target1.folderPath, + destination: path.join(path.dirname(target1.folderPath), "testing"), + }, + { type: "REFRESH" }, + ] + + ExplorerState.renameEpic(action$, null, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualActions => assert.deepEqual(actualActions, expected)) + }) + + it("Should send a notification on paste success", () => { + const action$ = ActionsObservable.of({ + type: "PASTE_SUCCESS", + moved: [{ node: target1, destination: "/another/test/dir" }], + } as ExplorerState.IPasteSuccessAction) + + const expected = [{ type: "NOTIFICATION_SENT", typeOfNotification: "PASTE_SUCCESS" }] + + ExplorerState.notificationEpic(action$, null, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualAction => assert.deepEqual(actualAction, expected)) + }) + + it("Should send a notification on paste fail", () => { + const action$ = ActionsObservable.of({ + type: "PASTE_FAIL", + } as ExplorerState.IPasteFailAction) + + const expected = [{ type: "NOTIFICATION_SENT", typeOfNotification: "PASTE_FAIL" }] + + ExplorerState.notificationEpic(action$, null, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualAction => assert.deepEqual(actualAction, expected)) + }) + + it("Should send a notification on rename success", () => { + const action$ = ActionsObservable.of({ + type: "RENAME_SUCCESS", + source: "/initial/test/dir", + destination: "/destination/test/dir", + targetType: "folder", + } as ExplorerState.IRenameSuccessAction) + + const expected = [{ type: "NOTIFICATION_SENT", typeOfNotification: "RENAME_SUCCESS" }] + + ExplorerState.notificationEpic(action$, null, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualAction => assert.deepEqual(actualAction, expected)) + }) + + it("Should send a notification on rename success", () => { + const action$ = ActionsObservable.of({ + type: "RENAME_FAIL", + } as ExplorerState.IRenameFailAction) + + const expected = [{ type: "NOTIFICATION_SENT", typeOfNotification: "RENAME_FAIL" }] + + ExplorerState.notificationEpic(action$, null, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualAction => assert.deepEqual(actualAction, expected)) + }) }) describe("Store utility helper tests", () => { @@ -429,6 +519,30 @@ describe("ExplorerStore", () => { }) assert.ok(!newState.undo.length) }) + + it("Should add a successful rename to undo register", () => { + const newState = yankRegisterReducer(clone(register), { + type: "RENAME_SUCCESS", + destination: path.basename(target1.folderPath) + "/rename", + source: target1.folderPath, + targetType: "folder", + }) + + assert.ok(newState.undo.length === 1) + }) + + it("Should clear the renaming if a rename cancel action is triggered", () => { + const state = { + ...clone(register), + rename: { + target: target1 as ExplorerNode, + active: true, + }, + } + const newState = yankRegisterReducer(state, { type: "RENAME_CANCEL" }) + assert.ok(!newState.rename.active) + assert.ok(!newState.rename.target) + }) }) }) }) diff --git a/jest.config.js b/jest.config.js index 646aba48e8..b2dd906656 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,6 +11,7 @@ module.exports = { Utility: "<rootDir>/ui-tests/mocks/Utility.ts", Configuration: "<rootDir>/ui-tests/mocks/Configuration.ts", classnames: "<rootDir>/ui-tests/mocks/classnames.ts", + KeyboardLayout: "<rootDir>/ui-tests/mocks/keyboardLayout.ts", }, snapshotSerializers: ["enzyme-to-json/serializer"], transform: { diff --git a/package.json b/package.json index 60fbdfacee..d9a12ff841 100644 --- a/package.json +++ b/package.json @@ -690,7 +690,8 @@ "dompurify": "^1.0.3", "electron-settings": "^3.1.4", "find-up": "2.1.0", - "keyboard-layout": "2.0.13", + "fs-extra": "^5.0.0", + "keyboard-layout": "^2.0.13", "marked": "^0.3.6", "minimist": "1.2.0", "msgpack-lite": "0.1.26", @@ -704,7 +705,6 @@ "react-dnd-html5-backend": "^2.5.4", "react-dom": "16.0.0", "redux-batched-subscribe": "^0.1.6", - "fs-extra": "^5.0.0", "shell-env": "^0.3.0", "shelljs": "0.7.7", "styled-components": "^2.3.0", diff --git a/ui-tests/NodeView.test.tsx b/ui-tests/NodeView.test.tsx new file mode 100644 index 0000000000..53f8967613 --- /dev/null +++ b/ui-tests/NodeView.test.tsx @@ -0,0 +1,69 @@ +import { mount, shallow } from "enzyme" +import { shallowToJson } from "enzyme-to-json" +import * as React from "react" + +import { DragAndDrop } from "./../browser/src/Services/DragAndDrop" +import { ExplorerNode } from "./../browser/src/Services/Explorer/ExplorerSelectors" +import { NodeView, NodeWrapper } from "./../browser/src/Services/Explorer/ExplorerView" +import { TextInputView } from "./../browser/src/UI/components/LightweightText" + +describe("<NodeView />", () => { + const testNode = { + id: "2", + filePath: "/test/a/file.txt", + type: "file", + modified: false, + name: "file.txt", + indentationLevel: 2, + } as ExplorerNode + + const Node = ( + <NodeView + yanked={[] as string[]} + isRenaming={testNode} + moveFileOrFolder={() => ({})} + node={testNode} + isSelected={false} + onClick={() => ({})} + onCancelRename={() => ({})} + onCompleteRename={() => ({})} + /> + ) + it("Should render without crashing", () => { + const wrapper = shallow(Node) + expect(wrapper.length).toEqual(1) + }) + + it("Should render and input element if the selected element is renaming", () => { + const wrapper = shallow( + <NodeView + yanked={[] as string[]} + isRenaming={testNode} + moveFileOrFolder={() => ({})} + node={testNode} + isSelected={true} + onClick={() => ({})} + onCancelRename={() => ({})} + onCompleteRename={() => ({})} + />, + ) + + const input = wrapper.find(TextInputView) + expect(input.length).toEqual(1) + }) + + it("Should render the node if the selected element is not renaming", () => { + const wrapper = shallow(Node) + expect( + wrapper + .find(NodeWrapper) + .dive() + .find(DragAndDrop), + ).toHaveLength(1) + }) + + it("Should match the snapshot", () => { + const wrapper = shallow(Node) + expect(shallowToJson(wrapper)).toMatchSnapshot() + }) +}) diff --git a/ui-tests/__snapshots__/NodeView.test.tsx.snap b/ui-tests/__snapshots__/NodeView.test.tsx.snap new file mode 100644 index 0000000000..d31ffa67f0 --- /dev/null +++ b/ui-tests/__snapshots__/NodeView.test.tsx.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<NodeView /> Should match the snapshot 1`] = ` +<styled.div + innerRef={[Function]} + style={ + Object { + "cursor": "pointer", + } + } +> + <DropTarget(DragSource(DragAndDrop)) + accepts={ + Array [ + "FILE", + "FOLDER", + ] + } + dragTarget="FILE" + isValidDrop={[Function]} + node={ + Object { + "filePath": "/test/a/file.txt", + "id": "2", + "indentationLevel": 2, + "modified": false, + "name": "file.txt", + "type": "file", + } + } + onDrop={[Function]} + render={[Function]} + /> +</styled.div> +`; diff --git a/ui-tests/mocks/Utility.ts b/ui-tests/mocks/Utility.ts index a77f9620b1..fccd70836d 100644 --- a/ui-tests/mocks/Utility.ts +++ b/ui-tests/mocks/Utility.ts @@ -1 +1,2 @@ export const diff = jest.fn() +export const createCompletablePromise = jest.fn() diff --git a/ui-tests/mocks/keyboardLayout.ts b/ui-tests/mocks/keyboardLayout.ts new file mode 100644 index 0000000000..2b0d4d98f0 --- /dev/null +++ b/ui-tests/mocks/keyboardLayout.ts @@ -0,0 +1,14 @@ +const getCurrentKeyboardLanguage = jest.fn() + +export const KeyboardLayoutManager = jest.fn().mockImplementation(() => { + return { + onKeyMapChanged: { + subscribe: jest.fn(), + dispatch: jest.fn(), + }, + getCurrentKeyMap: jest.fn(), + getCurrentKeyboardLanguage, + } +}) + +export default KeyboardLayoutManager diff --git a/yarn.lock b/yarn.lock index f209486ddf..e8598887cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6071,7 +6071,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -keyboard-layout@2.0.13: +keyboard-layout@^2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/keyboard-layout/-/keyboard-layout-2.0.13.tgz#5b4f5c25835e5d221a7b9da897663100d897487d" dependencies: From ba5e4dee769ca3b0375b2854ababb3866afcc64f Mon Sep 17 00:00:00 2001 From: Ryan C <ryan@ryancross.xyz> Date: Tue, 24 Apr 2018 12:20:33 +0100 Subject: [PATCH 52/59] Add back cache to VSCode scorer. (#2126) * Add a cache back. There is a todo explaining possible further work, after testing. * Fix tests. * Fix lint issues. --- .../QuickOpen/Scorer/OniQuickOpenScorer.ts | 13 ++++++-- .../QuickOpen/Scorer/QuickOpenScorer.ts | 30 +++++++++---------- .../src/Services/QuickOpen/VSCodeFilter.ts | 17 +++++++++-- .../Services/QuickOpen/VSCodeFilterTests.ts | 13 ++++++-- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/browser/src/Services/QuickOpen/Scorer/OniQuickOpenScorer.ts b/browser/src/Services/QuickOpen/Scorer/OniQuickOpenScorer.ts index 39a162c138..497881b82e 100644 --- a/browser/src/Services/QuickOpen/Scorer/OniQuickOpenScorer.ts +++ b/browser/src/Services/QuickOpen/Scorer/OniQuickOpenScorer.ts @@ -5,6 +5,7 @@ import { IItemScore, prepareQuery, scoreItem, + ScorerCache, } from "./QuickOpenScorer" import { nativeSep } from "./Utilities" @@ -24,7 +25,12 @@ class OniAccessor implements IItemAccessor<any> { } } -export function scoreItemOni(resultObject: any, searchString: string, fuzzy: boolean): IItemScore { +export function scoreItemOni( + resultObject: any, + searchString: string, + fuzzy: boolean, + cache: ScorerCache, +): IItemScore { if (!searchString) { return NO_ITEM_SCORE } @@ -37,7 +43,7 @@ export function scoreItemOni(resultObject: any, searchString: string, fuzzy: boo const accessor = new OniAccessor() - return scoreItem(resultObject, query, fuzzy, accessor) + return scoreItem(resultObject, query, fuzzy, accessor, cache) } export function compareItemsByScoreOni( @@ -45,6 +51,7 @@ export function compareItemsByScoreOni( resultObjectB: any, searchString: string, fuzzy: boolean, + cache: ScorerCache, ): number { if (!searchString) { return 0 @@ -58,7 +65,7 @@ export function compareItemsByScoreOni( const accessor = new OniAccessor() - return compareItemsByScore(resultObjectA, resultObjectB, query, fuzzy, accessor) + return compareItemsByScore(resultObjectA, resultObjectB, query, fuzzy, accessor, cache) } export const getHighlightsFromResult = (result: IMatch[]): number[] => { diff --git a/browser/src/Services/QuickOpen/Scorer/QuickOpenScorer.ts b/browser/src/Services/QuickOpen/Scorer/QuickOpenScorer.ts index 965f5df118..3cd6477ffb 100644 --- a/browser/src/Services/QuickOpen/Scorer/QuickOpenScorer.ts +++ b/browser/src/Services/QuickOpen/Scorer/QuickOpenScorer.ts @@ -343,7 +343,7 @@ export function scoreItem<T>( query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, - // cache: ScorerCache, + cache: ScorerCache, ): IItemScore { if (!item || !query.value) { return NO_ITEM_SCORE // we need an item and query to score on at least @@ -356,20 +356,20 @@ export function scoreItem<T>( const description = accessor.getItemDescription(item) - // let cacheHash: string - // if (description) { - // cacheHash = `${label}${description}${query.value}${fuzzy}` - // } else { - // cacheHash = `${label}${query.value}${fuzzy}` - // } + let cacheHash: string + if (description) { + cacheHash = `${label}${description}${query.value}${fuzzy}` + } else { + cacheHash = `${label}${query.value}${fuzzy}` + } - // const cached = cache[cacheHash] - // if (cached) { - // return cached - // } + const cached = cache[cacheHash] + if (cached) { + return cached + } const itemScore = doScoreItem(label, description, accessor.getItemPath(item), query, fuzzy) - // cache[cacheHash] = itemScore + cache[cacheHash] = itemScore return itemScore } @@ -467,11 +467,11 @@ export function compareItemsByScore<T>( query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, - // cache: ScorerCache, + cache: ScorerCache, fallbackComparer = fallbackCompare, ): number { - const itemScoreA = scoreItem(itemA, query, fuzzy, accessor) - const itemScoreB = scoreItem(itemB, query, fuzzy, accessor) + const itemScoreA = scoreItem(itemA, query, fuzzy, accessor, cache) + const itemScoreB = scoreItem(itemB, query, fuzzy, accessor, cache) const scoreA = itemScoreA.score const scoreB = itemScoreB.score diff --git a/browser/src/Services/QuickOpen/VSCodeFilter.ts b/browser/src/Services/QuickOpen/VSCodeFilter.ts index 56444293fd..aaf56ee2e4 100644 --- a/browser/src/Services/QuickOpen/VSCodeFilter.ts +++ b/browser/src/Services/QuickOpen/VSCodeFilter.ts @@ -15,6 +15,7 @@ import { } from "./Scorer/OniQuickOpenScorer" import { IMenuOptionWithHighlights, shouldFilterbeCaseSensitive } from "./../Menu" +import { ScorerCache } from "./Scorer/QuickOpenScorer" export const vsCodeFilter = ( options: Oni.Menu.MenuOption[], @@ -49,7 +50,16 @@ export const vsCodeFilter = ( ? listOfSearchTerms.slice(1).join("") + listOfSearchTerms[0] : listOfSearchTerms[0] - const filteredOptions = processSearchTerm(vsCodeSearchString, options) + // Adds a cache for the scores. This is needed to stop the final score + // compare from repeating all the scoring logic again. + // Currently, this only persists for the current search, which will speed + // up that search only. + // TODO: Is it worth instead persisting this cache? + // Plus side is repeated searches are fast. + // Down side is there will be a lot of rubbish being stored too. + const cache: ScorerCache = {} + + const filteredOptions = processSearchTerm(vsCodeSearchString, options, cache) const ret = filteredOptions.filter(fo => { if (fo.score === 0) { @@ -59,15 +69,16 @@ export const vsCodeFilter = ( } }) - return ret.sort((e1, e2) => compareItemsByScoreOni(e1, e2, vsCodeSearchString, true)) + return ret.sort((e1, e2) => compareItemsByScoreOni(e1, e2, vsCodeSearchString, true, cache)) } export const processSearchTerm = ( searchString: string, options: Oni.Menu.MenuOption[], + cache: ScorerCache, ): Oni.Menu.IMenuOptionWithHighlights[] => { const result: Oni.Menu.IMenuOptionWithHighlights[] = options.map(f => { - const itemScore = scoreItemOni(f, searchString, true) + const itemScore = scoreItemOni(f, searchString, true, cache) const detailHighlights = getHighlightsFromResult(itemScore.descriptionMatch) const labelHighlights = getHighlightsFromResult(itemScore.labelMatch) diff --git a/browser/test/Services/QuickOpen/VSCodeFilterTests.ts b/browser/test/Services/QuickOpen/VSCodeFilterTests.ts index a1f36c3233..ae78044320 100644 --- a/browser/test/Services/QuickOpen/VSCodeFilterTests.ts +++ b/browser/test/Services/QuickOpen/VSCodeFilterTests.ts @@ -3,9 +3,16 @@ */ import * as assert from "assert" +import { ScorerCache } from "../../../src/Services/QuickOpen/Scorer/QuickOpenScorer" import { processSearchTerm, vsCodeFilter } from "./../../../src/Services/QuickOpen/VSCodeFilter" describe("processSearchTerm", () => { + let cache: ScorerCache + + beforeEach(() => { + cache = {} + }) + it("Correctly matches word.", async () => { const testString = "src" const testList = [ @@ -13,7 +20,7 @@ describe("processSearchTerm", () => { { label: "index.ts", detail: "browser/test" }, ] - const result = processSearchTerm(testString, testList) + const result = processSearchTerm(testString, testList, cache) const filteredResult = result.filter(r => r.score !== 0) // Remove the score since it can change if we updated the @@ -39,7 +46,7 @@ describe("processSearchTerm", () => { { label: "index.ts", detail: "browser/SRC" }, ] - const result = processSearchTerm(testString, testList) + const result = processSearchTerm(testString, testList, cache) // Check the exact case match scores higher const lowercase = result.find(r => r.detail === "browser/src") @@ -57,7 +64,7 @@ describe("processSearchTerm", () => { { label: "index.ts", detail: "browser/test" }, ] - const result = processSearchTerm(testString, testList) + const result = processSearchTerm(testString, testList, cache) const filteredResult = result.filter(r => r.score !== 0) assert.deepEqual(filteredResult, []) From 479fd42a4912be847d69297f9ff81267804f160a Mon Sep 17 00:00:00 2001 From: Manuel Hornung <manuel@hornung.in> Date: Wed, 25 Apr 2018 03:24:37 +0200 Subject: [PATCH 53/59] Add experimental WebGL Renderer (#2120) * First version of the WebGL renderer with grayscale text antialias * Add CachedColorNormalizer and first attempt at background rendering * Get background renderer to work :) * Refactor WebGL code * Incorporate line padding into glyph positioning * Add configuration property for switching between canvas and WebGL renderer * Improve warning and tweak atlas padding --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 9 +- .../Renderer/WebGL/CachedColorNormalizer.ts | 18 + .../src/Renderer/WebGL/IColorNormalizer.ts | 3 + browser/src/Renderer/WebGL/WebGLAtlas.ts | 131 +++++++ browser/src/Renderer/WebGL/WebGLRenderer.ts | 157 ++++++++ .../src/Renderer/WebGL/WebGLSolidRenderer.ts | 233 ++++++++++++ .../src/Renderer/WebGL/WebGLTextRenderer.ts | 338 ++++++++++++++++++ browser/src/Renderer/WebGL/WebGLUtilities.ts | 57 +++ .../Configuration/DefaultConfiguration.ts | 2 + .../Configuration/IConfigurationValues.ts | 6 + browser/src/color-normalize.d.ts | 29 ++ browser/src/neovim/Screen.ts | 2 +- browser/tsconfig.json | 2 +- browser/tsconfig.test.json | 2 +- package.json | 2 + ui-tests/tsconfig.react.json | 2 +- yarn.lock | 126 +++++-- 17 files changed, 1074 insertions(+), 45 deletions(-) create mode 100644 browser/src/Renderer/WebGL/CachedColorNormalizer.ts create mode 100644 browser/src/Renderer/WebGL/IColorNormalizer.ts create mode 100644 browser/src/Renderer/WebGL/WebGLAtlas.ts create mode 100644 browser/src/Renderer/WebGL/WebGLRenderer.ts create mode 100644 browser/src/Renderer/WebGL/WebGLSolidRenderer.ts create mode 100644 browser/src/Renderer/WebGL/WebGLTextRenderer.ts create mode 100644 browser/src/Renderer/WebGL/WebGLUtilities.ts create mode 100644 browser/src/color-normalize.d.ts diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 7b90d56824..617a9eca76 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -33,7 +33,7 @@ import { NeovimScreen, NeovimWindowManager, } from "./../../neovim" -import { CanvasRenderer, INeovimRenderer } from "./../../Renderer" +import { INeovimRenderer } from "./../../Renderer" import { PluginManager } from "./../../Plugins/PluginManager" @@ -94,6 +94,8 @@ import WildMenu from "./../../UI/components/WildMenu" import { WelcomeBufferLayer } from "./WelcomeBufferLayer" +import { CanvasRenderer } from "../../Renderer/CanvasRenderer" +import { WebGLRenderer } from "../../Renderer/WebGL/WebGLRenderer" import { getInstance as getNotificationsInstance } from "./../../Services/Notifications" export class NeovimEditor extends Editor implements IEditor { @@ -292,7 +294,10 @@ export class NeovimEditor extends Editor implements IEditor { initVimNotification.show() } - this._renderer = new CanvasRenderer() + this._renderer = + this._configuration.getValue("editor.renderer") === "webgl" + ? new WebGLRenderer() + : new CanvasRenderer() this._rename = new Rename( this, diff --git a/browser/src/Renderer/WebGL/CachedColorNormalizer.ts b/browser/src/Renderer/WebGL/CachedColorNormalizer.ts new file mode 100644 index 0000000000..e68ae5b1ee --- /dev/null +++ b/browser/src/Renderer/WebGL/CachedColorNormalizer.ts @@ -0,0 +1,18 @@ +import * as normalizeColor from "color-normalize" +import { IColorNormalizer } from "./IColorNormalizer" + +export class CachedColorNormalizer implements IColorNormalizer { + private _cache = new Map<string, Float32Array>() + + public normalizeColor(cssColor: string): Float32Array { + const cachedRgba = this._cache.get(cssColor) + + if (cachedRgba) { + return cachedRgba + } else { + const rgba = normalizeColor.call(null, cssColor, "float32") + this._cache.set(cssColor, rgba) + return rgba + } + } +} diff --git a/browser/src/Renderer/WebGL/IColorNormalizer.ts b/browser/src/Renderer/WebGL/IColorNormalizer.ts new file mode 100644 index 0000000000..3591e34f1c --- /dev/null +++ b/browser/src/Renderer/WebGL/IColorNormalizer.ts @@ -0,0 +1,3 @@ +export interface IColorNormalizer { + normalizeColor(cssColor: string): Float32Array +} diff --git a/browser/src/Renderer/WebGL/WebGLAtlas.ts b/browser/src/Renderer/WebGL/WebGLAtlas.ts new file mode 100644 index 0000000000..d671917b73 --- /dev/null +++ b/browser/src/Renderer/WebGL/WebGLAtlas.ts @@ -0,0 +1,131 @@ +const defaultTextureSizeInPixels = 512 +const glyphPaddingInPixels = 0 + +export interface IWebGLAtlasOptions { + fontFamily: string + fontSize: string + lineHeightInPixels: number + linePaddingInPixels: number + devicePixelRatio: number + offsetGlyphVariantCount: number +} + +export interface WebGLGlyph { + width: number + height: number + textureWidth: number + textureHeight: number + textureU: number + textureV: number + variantOffset: number + subpixelWidth: number +} + +export class WebGLAtlas { + private _glyphContext: CanvasRenderingContext2D + private _glyphs = new Map<string, Map<number, WebGLGlyph>>() + private _nextX = 0 + private _nextY = 0 + private _textureChangedSinceLastUpload = false + private _texture: WebGLTexture + private _textureSize: number + private _uvScale: number + + constructor(private _gl: WebGL2RenderingContext, private _options: IWebGLAtlasOptions) { + this._textureSize = defaultTextureSizeInPixels * _options.devicePixelRatio + this._uvScale = 1 / this._textureSize + + const glyphCanvas = document.createElement("canvas") + glyphCanvas.width = this._textureSize + glyphCanvas.height = this._textureSize + this._glyphContext = glyphCanvas.getContext("2d", { alpha: false }) + this._glyphContext.font = `${this._options.fontSize} ${this._options.fontFamily}` + this._glyphContext.fillStyle = "white" + this._glyphContext.textBaseline = "top" + this._glyphContext.scale(_options.devicePixelRatio, _options.devicePixelRatio) + this._glyphContext.imageSmoothingEnabled = false + + this._texture = _gl.createTexture() + _gl.bindTexture(_gl.TEXTURE_2D, this._texture) + _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR) + _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE) + _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE) + this._textureChangedSinceLastUpload = true + this.uploadTexture() + } + + public getGlyph(text: string, variantIndex: number) { + let glyphVariants = this._glyphs.get(text) + if (!glyphVariants) { + glyphVariants = new Map() + this._glyphs.set(text, glyphVariants) + } + + let glyph = glyphVariants.get(variantIndex) + if (!glyph) { + glyph = this._rasterizeGlyph(text, variantIndex) + glyphVariants.set(variantIndex, glyph) + } + + return glyph + } + + public uploadTexture() { + if (this._textureChangedSinceLastUpload) { + this._gl.texImage2D( + this._gl.TEXTURE_2D, + 0, + this._gl.RGBA, + this._textureSize, + this._textureSize, + 0, + this._gl.RGBA, + this._gl.UNSIGNED_BYTE, + this._glyphContext.canvas, + ) + this._textureChangedSinceLastUpload = false + } + } + + private _rasterizeGlyph(text: string, variantIndex: number) { + this._textureChangedSinceLastUpload = true + + const { + devicePixelRatio, + lineHeightInPixels, + linePaddingInPixels, + offsetGlyphVariantCount, + } = this._options + const variantOffset = variantIndex / offsetGlyphVariantCount + + const height = lineHeightInPixels + const { width: subpixelWidth } = this._glyphContext.measureText(text) + const width = Math.ceil(variantOffset) + Math.ceil(subpixelWidth) + + if ((this._nextX + width) * devicePixelRatio > this._textureSize) { + this._nextX = 0 + this._nextY = Math.ceil(this._nextY + height + glyphPaddingInPixels) + } + + if ((this._nextY + height) * devicePixelRatio > this._textureSize) { + // TODO implement a fallback instead of just throwing + throw new Error("Texture is too small") + } + + const x = this._nextX + const y = this._nextY + this._glyphContext.fillText(text, x + variantOffset, y + linePaddingInPixels / 2) + this._nextX += width + + return { + textureU: x * devicePixelRatio * this._uvScale, + textureV: y * devicePixelRatio * this._uvScale, + textureWidth: width * devicePixelRatio * this._uvScale, + textureHeight: height * devicePixelRatio * this._uvScale, + width: width * devicePixelRatio, + height: height * devicePixelRatio, + subpixelWidth: subpixelWidth * devicePixelRatio, + variantOffset, + } as WebGLGlyph + } +} diff --git a/browser/src/Renderer/WebGL/WebGLRenderer.ts b/browser/src/Renderer/WebGL/WebGLRenderer.ts new file mode 100644 index 0000000000..b7816bb346 --- /dev/null +++ b/browser/src/Renderer/WebGL/WebGLRenderer.ts @@ -0,0 +1,157 @@ +import { INeovimRenderer } from ".." +import { IScreen } from "../../neovim" +import { CachedColorNormalizer } from "./CachedColorNormalizer" +import { IColorNormalizer } from "./IColorNormalizer" +import { IWebGLAtlasOptions } from "./WebGLAtlas" +import { WebGLSolidRenderer } from "./WebGLSolidRenderer" +import { WebGlTextRenderer } from "./WebGLTextRenderer" + +export class WebGLRenderer implements INeovimRenderer { + private _editorElement: HTMLElement + private _colorNormalizer: IColorNormalizer + private _previousAtlasOptions: IWebGLAtlasOptions + + private _gl: WebGL2RenderingContext + private _solidRenderer: WebGLSolidRenderer + private _textRenderer: WebGlTextRenderer + + public start(editorElement: HTMLElement): void { + this._editorElement = editorElement + this._colorNormalizer = new CachedColorNormalizer() + + const canvasElement = document.createElement("canvas") + canvasElement.style.width = `100%` + canvasElement.style.height = `100%` + + this._editorElement.innerHTML = "" + this._editorElement.appendChild(canvasElement) + + this._gl = canvasElement.getContext("webgl2") as WebGL2RenderingContext + } + + public redrawAll(screenInfo: IScreen): void { + this._updateCanvasDimensions() + this._createNewRendererIfRequired(screenInfo) + this._clear(screenInfo.backgroundColor) + this._draw(screenInfo) + } + + public draw(screenInfo: IScreen): void { + this.redrawAll(screenInfo) + } + + public onAction(action: any): void { + // do nothing + } + + private _updateCanvasDimensions() { + const devicePixelRatio = window.devicePixelRatio + this._gl.canvas.width = this._editorElement.offsetWidth * devicePixelRatio + this._gl.canvas.height = this._editorElement.offsetHeight * devicePixelRatio + } + + private _createNewRendererIfRequired({ + width: columnCount, + height: rowCount, + fontWidthInPixels, + fontHeightInPixels, + linePaddingInPixels, + fontFamily, + fontSize, + }: IScreen) { + const devicePixelRatio = window.devicePixelRatio + const offsetGlyphVariantCount = Math.max(4 / devicePixelRatio, 1) + const atlasOptions = { + fontFamily, + fontSize, + lineHeightInPixels: fontHeightInPixels, + linePaddingInPixels, + devicePixelRatio, + offsetGlyphVariantCount, + } as IWebGLAtlasOptions + + if ( + !this._solidRenderer || + !this._textRenderer || + !this._previousAtlasOptions || + !isShallowEqual(this._previousAtlasOptions, atlasOptions) + ) { + this._solidRenderer = new WebGLSolidRenderer( + this._gl, + this._colorNormalizer, + atlasOptions.devicePixelRatio, + ) + this._textRenderer = new WebGlTextRenderer( + this._gl, + this._colorNormalizer, + atlasOptions, + ) + this._previousAtlasOptions = atlasOptions + } + } + + private _clear(backgroundColor: string) { + const backgroundColorToUse = backgroundColor || "black" + const normalizedBackgroundColor = this._colorNormalizer.normalizeColor(backgroundColorToUse) + this._gl.clearColor( + normalizedBackgroundColor[0], + normalizedBackgroundColor[1], + normalizedBackgroundColor[2], + normalizedBackgroundColor[3], + ) + this._gl.clear(this._gl.COLOR_BUFFER_BIT) + } + + private _draw({ + width: columnCount, + height: rowCount, + fontWidthInPixels, + fontHeightInPixels, + getCell, + foregroundColor, + backgroundColor, + }: IScreen) { + const canvasWidth = this._gl.canvas.width + const canvasHeight = this._gl.canvas.height + const viewportScaleX = 2 / canvasWidth + const viewportScaleY = -2 / canvasHeight + this._gl.viewport(0, 0, canvasWidth, canvasHeight) + + this._solidRenderer.draw( + columnCount, + rowCount, + getCell, + fontWidthInPixels, + fontHeightInPixels, + backgroundColor, + viewportScaleX, + viewportScaleY, + ) + this._textRenderer.draw( + columnCount, + rowCount, + getCell, + fontWidthInPixels, + fontHeightInPixels, + foregroundColor, + viewportScaleX, + viewportScaleY, + ) + } +} + +function isShallowEqual<T>(objectA: T, objectB: T) { + for (const key in objectA) { + if (!(key in objectB) || objectA[key] !== objectB[key]) { + return false + } + } + + for (const key in objectB) { + if (!(key in objectA) || objectA[key] !== objectB[key]) { + return false + } + } + + return true +} diff --git a/browser/src/Renderer/WebGL/WebGLSolidRenderer.ts b/browser/src/Renderer/WebGL/WebGLSolidRenderer.ts new file mode 100644 index 0000000000..dadafec5ed --- /dev/null +++ b/browser/src/Renderer/WebGL/WebGLSolidRenderer.ts @@ -0,0 +1,233 @@ +import { ICell } from "../../neovim" +import { IColorNormalizer } from "./IColorNormalizer" +import { + createProgram, + createUnitQuadElementIndicesBuffer, + createUnitQuadVerticesBuffer, +} from "./WebGLUtilities" + +// tslint:disable-next-line:no-bitwise +const maxCellInstances = 1 << 14 // TODO find a reasonable way of determining this +const solidInstanceFieldCount = 8 +const solidInstanceSizeInBytes = solidInstanceFieldCount * Float32Array.BYTES_PER_ELEMENT + +const vertexShaderAttributes = { + unitQuadVertex: 0, + targetOrigin: 1, + targetSize: 2, + colorRGBA: 3, +} + +const vertexShaderSource = ` + #version 300 es + + layout (location = 0) in vec2 unitQuadVertex; + layout (location = 1) in vec2 targetOrigin; + layout (location = 2) in vec2 targetSize; + layout (location = 3) in vec4 colorRGBA; + flat out vec4 color; + + uniform vec2 viewportScale; + + void main() { + vec2 targetPixelPosition = targetOrigin + unitQuadVertex * targetSize; + vec2 targetPosition = targetPixelPosition * viewportScale + vec2(-1.0, 1.0); + gl_Position = vec4(targetPosition, 0.0, 1.0); + color = colorRGBA; + } +`.trim() + +const fragmentShaderSource = ` + #version 300 es + + precision mediump float; + + flat in vec4 color; + layout (location = 0) out vec4 outColor; + + void main() { + outColor = color; + } +`.trim() + +export class WebGLSolidRenderer { + private _program: WebGLProgram + private _viewportScaleLocation: WebGLUniformLocation + private _unitQuadVerticesBuffer: WebGLBuffer + private _unitQuadElementIndicesBuffer: WebGLBuffer + private _solidInstances: Float32Array + private _solidInstancesBuffer: WebGLBuffer + private _vertexArrayObject: WebGLVertexArrayObject + + constructor( + private _gl: WebGL2RenderingContext, + private _colorNormalizer: IColorNormalizer, + private _devicePixelRatio: number, + ) { + this._program = createProgram(this._gl, vertexShaderSource, fragmentShaderSource) + this._viewportScaleLocation = this._gl.getUniformLocation(this._program, "viewportScale") + + this.createBuffers() + this.createVertexArrayObject() + } + + public draw( + columnCount: number, + rowCount: number, + getCell: (columnIndex: number, rowIndex: number) => ICell, + fontWidthInPixels: number, + fontHeightInPixels: number, + defaultBackgroundColor: string, + viewportScaleX: number, + viewportScaleY: number, + ) { + const solidInstanceCount = this.populateSolidInstances( + columnCount, + rowCount, + getCell, + fontWidthInPixels, + fontHeightInPixels, + defaultBackgroundColor, + ) + this.drawSolidInstances(solidInstanceCount, viewportScaleX, viewportScaleY) + } + + private createBuffers() { + this._unitQuadVerticesBuffer = createUnitQuadVerticesBuffer(this._gl) + this._unitQuadElementIndicesBuffer = createUnitQuadElementIndicesBuffer(this._gl) + this._solidInstances = new Float32Array(maxCellInstances * solidInstanceFieldCount) + this._solidInstancesBuffer = this._gl.createBuffer() + } + + private createVertexArrayObject() { + this._vertexArrayObject = this._gl.createVertexArray() + this._gl.bindVertexArray(this._vertexArrayObject) + + this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, this._unitQuadElementIndicesBuffer) + + this._gl.bindBuffer(this._gl.ARRAY_BUFFER, this._unitQuadVerticesBuffer) + this._gl.enableVertexAttribArray(vertexShaderAttributes.unitQuadVertex) + this._gl.vertexAttribPointer( + vertexShaderAttributes.unitQuadVertex, + 2, + this._gl.FLOAT, + false, + 0, + 0, + ) + + this._gl.bindBuffer(this._gl.ARRAY_BUFFER, this._solidInstancesBuffer) + + this._gl.enableVertexAttribArray(vertexShaderAttributes.targetOrigin) + this._gl.vertexAttribPointer( + vertexShaderAttributes.targetOrigin, + 2, + this._gl.FLOAT, + false, + solidInstanceSizeInBytes, + 0, + ) + this._gl.vertexAttribDivisor(vertexShaderAttributes.targetOrigin, 1) + + this._gl.enableVertexAttribArray(vertexShaderAttributes.targetSize) + this._gl.vertexAttribPointer( + vertexShaderAttributes.targetSize, + 2, + this._gl.FLOAT, + false, + solidInstanceSizeInBytes, + 2 * Float32Array.BYTES_PER_ELEMENT, + ) + this._gl.vertexAttribDivisor(vertexShaderAttributes.targetSize, 1) + + this._gl.enableVertexAttribArray(vertexShaderAttributes.colorRGBA) + this._gl.vertexAttribPointer( + vertexShaderAttributes.colorRGBA, + 4, + this._gl.FLOAT, + false, + solidInstanceSizeInBytes, + 4 * Float32Array.BYTES_PER_ELEMENT, + ) + this._gl.vertexAttribDivisor(vertexShaderAttributes.colorRGBA, 1) + } + + private populateSolidInstances( + columnCount: number, + rowCount: number, + getCell: (columnIndex: number, rowIndex: number) => ICell, + fontWidthInPixels: number, + fontHeightInPixels: number, + defaultBackgroundColor: string, + ) { + const pixelRatioAdaptedFontWidth = fontWidthInPixels * this._devicePixelRatio + const pixelRatioAdaptedFontHeight = fontHeightInPixels * this._devicePixelRatio + + let solidCellCount = 0 + let y = 0 + + // TODO refactor this to not be as reliant on mutations + for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) { + let x = 0 + + for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) { + const cell = getCell(columnIndex, rowIndex) + + if (cell.backgroundColor && cell.backgroundColor !== defaultBackgroundColor) { + const colorToUse = cell.backgroundColor || defaultBackgroundColor || "black" + const normalizedBackgroundColor = this._colorNormalizer.normalizeColor( + colorToUse, + ) + + this.updateSolidInstance( + solidCellCount, + x, + y, + pixelRatioAdaptedFontWidth, + pixelRatioAdaptedFontHeight, + normalizedBackgroundColor, + ) + + solidCellCount++ + } + x += pixelRatioAdaptedFontWidth + } + + y += pixelRatioAdaptedFontHeight + } + + return solidCellCount + } + + private drawSolidInstances(solidCount: number, viewportScaleX: number, viewportScaleY: number) { + this._gl.bindVertexArray(this._vertexArrayObject) + this._gl.disable(this._gl.BLEND) + this._gl.useProgram(this._program) + this._gl.uniform2f(this._viewportScaleLocation, viewportScaleX, viewportScaleY) + this._gl.bindBuffer(this._gl.ARRAY_BUFFER, this._solidInstancesBuffer) + this._gl.bufferData(this._gl.ARRAY_BUFFER, this._solidInstances, this._gl.STREAM_DRAW) + this._gl.drawElementsInstanced(this._gl.TRIANGLES, 6, this._gl.UNSIGNED_BYTE, 0, solidCount) + } + + private updateSolidInstance( + index: number, + x: number, + y: number, + width: number, + height: number, + color: Float32Array, + ) { + const startOffset = solidInstanceFieldCount * index + // targetOrigin + this._solidInstances[0 + startOffset] = x + this._solidInstances[1 + startOffset] = y + // targetSize + this._solidInstances[2 + startOffset] = width + this._solidInstances[3 + startOffset] = height + // colorRGBA + this._solidInstances[4 + startOffset] = color[0] + this._solidInstances[5 + startOffset] = color[1] + this._solidInstances[6 + startOffset] = color[2] + this._solidInstances[7 + startOffset] = color[3] + } +} diff --git a/browser/src/Renderer/WebGL/WebGLTextRenderer.ts b/browser/src/Renderer/WebGL/WebGLTextRenderer.ts new file mode 100644 index 0000000000..a3a36124ca --- /dev/null +++ b/browser/src/Renderer/WebGL/WebGLTextRenderer.ts @@ -0,0 +1,338 @@ +import { ICell } from "../../neovim" +import { IColorNormalizer } from "./IColorNormalizer" +import { IWebGLAtlasOptions, WebGLAtlas, WebGLGlyph } from "./WebGLAtlas" +import { + createProgram, + createUnitQuadElementIndicesBuffer, + createUnitQuadVerticesBuffer, +} from "./WebGLUtilities" + +// tslint:disable-next-line:no-bitwise +const maxGlyphInstances = 1 << 14 // TODO find a reasonable way of determining this +const glyphInstanceFieldCount = 12 +const glyphInstanceSizeInBytes = glyphInstanceFieldCount * Float32Array.BYTES_PER_ELEMENT + +const vertexShaderAttributes = { + unitQuadVertex: 0, + targetOrigin: 1, + targetSize: 2, + textColorRGBA: 3, + atlasOrigin: 4, + atlasSize: 5, +} + +const vertexShaderSource = ` + #version 300 es + + layout (location = 0) in vec2 unitQuadVertex; + layout (location = 1) in vec2 targetOrigin; + layout (location = 2) in vec2 targetSize; + layout (location = 3) in vec4 textColorRGBA; + layout (location = 4) in vec2 atlasOrigin; + layout (location = 5) in vec2 atlasSize; + + uniform vec2 viewportScale; + + flat out vec4 textColor; + out vec2 atlasPosition; + + void main() { + vec2 targetPixelPosition = targetOrigin + unitQuadVertex * targetSize; + vec2 targetPosition = targetPixelPosition * viewportScale + vec2(-1.0, 1.0); + gl_Position = vec4(targetPosition, 0.0, 1.0); + textColor = textColorRGBA; + atlasPosition = atlasOrigin + unitQuadVertex * atlasSize; + } +`.trim() + +const firstPassFragmentShaderSource = ` + #version 300 es + + precision mediump float; + + layout(location = 0) out vec4 outColor; + flat in vec4 textColor; + in vec2 atlasPosition; + + uniform sampler2D atlasTexture; + + void main() { + vec4 atlasColor = texture(atlasTexture, atlasPosition); + outColor = textColor.a * atlasColor; + } +`.trim() + +const secondPassFragmentShaderSource = ` + #version 300 es + + precision mediump float; + + layout(location = 0) out vec4 outColor; + flat in vec4 textColor; + in vec2 atlasPosition; + + uniform sampler2D atlasTexture; + + void main() { + vec3 atlasColor = texture(atlasTexture, atlasPosition).rgb; + vec3 outColorRGB = atlasColor * textColor.rgb; + float outColorA = max(outColorRGB.r, max(outColorRGB.g, outColorRGB.b)); + outColor = vec4(outColorRGB, outColorA); + } +`.trim() + +const isWhiteSpace = (text: string) => text === null || text === "" || text === " " + +export class WebGlTextRenderer { + private _atlas: WebGLAtlas + private _subpixelDivisor: number + private _devicePixelRatio: number + + private _firstPassProgram: WebGLProgram + private _firstPassViewportScaleLocation: WebGLUniformLocation + private _secondPassProgram: WebGLProgram + private _secondPassViewportScaleLocation: WebGLUniformLocation + private _unitQuadVerticesBuffer: WebGLBuffer + private _unitQuadElementIndicesBuffer: WebGLBuffer + private _glyphInstances: Float32Array + private _glyphInstancesBuffer: WebGLBuffer + private _vertexArrayObject: WebGLVertexArrayObject + + constructor( + private _gl: WebGL2RenderingContext, + private _colorNormalizer: IColorNormalizer, + atlasOptions: IWebGLAtlasOptions, + ) { + this._devicePixelRatio = atlasOptions.devicePixelRatio + this._subpixelDivisor = atlasOptions.offsetGlyphVariantCount + this._atlas = new WebGLAtlas(this._gl, atlasOptions) + + this._firstPassProgram = createProgram( + this._gl, + vertexShaderSource, + firstPassFragmentShaderSource, + ) + this._secondPassProgram = createProgram( + this._gl, + vertexShaderSource, + secondPassFragmentShaderSource, + ) + + this._firstPassViewportScaleLocation = this._gl.getUniformLocation( + this._firstPassProgram, + "viewportScale", + ) + this._secondPassViewportScaleLocation = this._gl.getUniformLocation( + this._secondPassProgram, + "viewportScale", + ) + + this.createBuffers() + this.createVertexArrayObject() + } + + public draw( + columnCount: number, + rowCount: number, + getCell: (columnIndex: number, rowIndex: number) => ICell, + fontWidthInPixels: number, + fontHeightInPixels: number, + defaultForegroundColor: string, + viewportScaleX: number, + viewportScaleY: number, + ) { + const glyphInstanceCount = this.populateGlyphInstances( + columnCount, + rowCount, + getCell, + fontWidthInPixels, + fontHeightInPixels, + defaultForegroundColor, + ) + this.drawGlyphInstances(glyphInstanceCount, viewportScaleX, viewportScaleY) + } + + private createBuffers() { + this._unitQuadVerticesBuffer = createUnitQuadVerticesBuffer(this._gl) + this._unitQuadElementIndicesBuffer = createUnitQuadElementIndicesBuffer(this._gl) + this._glyphInstances = new Float32Array(maxGlyphInstances * glyphInstanceFieldCount) + this._glyphInstancesBuffer = this._gl.createBuffer() + } + + private createVertexArrayObject() { + this._vertexArrayObject = this._gl.createVertexArray() + this._gl.bindVertexArray(this._vertexArrayObject) + + this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, this._unitQuadElementIndicesBuffer) + + this._gl.bindBuffer(this._gl.ARRAY_BUFFER, this._unitQuadVerticesBuffer) + this._gl.enableVertexAttribArray(vertexShaderAttributes.unitQuadVertex) + this._gl.vertexAttribPointer( + vertexShaderAttributes.unitQuadVertex, + 2, + this._gl.FLOAT, + false, + 0, + 0, + ) + + this._gl.bindBuffer(this._gl.ARRAY_BUFFER, this._glyphInstancesBuffer) + + this._gl.enableVertexAttribArray(vertexShaderAttributes.targetOrigin) + this._gl.vertexAttribPointer( + vertexShaderAttributes.targetOrigin, + 2, + this._gl.FLOAT, + false, + glyphInstanceSizeInBytes, + 0, + ) + this._gl.vertexAttribDivisor(vertexShaderAttributes.targetOrigin, 1) + + this._gl.enableVertexAttribArray(vertexShaderAttributes.targetSize) + this._gl.vertexAttribPointer( + vertexShaderAttributes.targetSize, + 2, + this._gl.FLOAT, + false, + glyphInstanceSizeInBytes, + 2 * Float32Array.BYTES_PER_ELEMENT, + ) + this._gl.vertexAttribDivisor(vertexShaderAttributes.targetSize, 1) + + this._gl.enableVertexAttribArray(vertexShaderAttributes.textColorRGBA) + this._gl.vertexAttribPointer( + vertexShaderAttributes.textColorRGBA, + 4, + this._gl.FLOAT, + false, + glyphInstanceSizeInBytes, + 4 * Float32Array.BYTES_PER_ELEMENT, + ) + this._gl.vertexAttribDivisor(vertexShaderAttributes.textColorRGBA, 1) + + this._gl.enableVertexAttribArray(vertexShaderAttributes.atlasOrigin) + this._gl.vertexAttribPointer( + vertexShaderAttributes.atlasOrigin, + 2, + this._gl.FLOAT, + false, + glyphInstanceSizeInBytes, + 8 * Float32Array.BYTES_PER_ELEMENT, + ) + this._gl.vertexAttribDivisor(vertexShaderAttributes.atlasOrigin, 1) + + this._gl.enableVertexAttribArray(vertexShaderAttributes.atlasSize) + this._gl.vertexAttribPointer( + vertexShaderAttributes.atlasSize, + 2, + this._gl.FLOAT, + false, + glyphInstanceSizeInBytes, + 10 * Float32Array.BYTES_PER_ELEMENT, + ) + this._gl.vertexAttribDivisor(vertexShaderAttributes.atlasSize, 1) + } + + private populateGlyphInstances( + columnCount: number, + rowCount: number, + getCell: (columnIndex: number, rowIndex: number) => ICell, + fontWidthInPixels: number, + fontHeightInPixels: number, + defaultForegroundColor: string, + ) { + const pixelRatioAdaptedFontWidth = fontWidthInPixels * this._devicePixelRatio + const pixelRatioAdaptedFontHeight = fontHeightInPixels * this._devicePixelRatio + + let glyphCount = 0 + let y = 0 + + // TODO refactor this to not be as reliant on mutations + for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) { + let x = 0 + + for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) { + const cell = getCell(columnIndex, rowIndex) + const char = cell.character + if (!isWhiteSpace(char)) { + const variantIndex = + Math.round(x * this._subpixelDivisor) % this._subpixelDivisor + const glyph = this._atlas.getGlyph(char, variantIndex) + const colorToUse = cell.foregroundColor || defaultForegroundColor || "white" + const normalizedTextColor = this._colorNormalizer.normalizeColor(colorToUse) + + this.updateGlyphInstance( + glyphCount, + Math.round(x - glyph.variantOffset), + y, + glyph, + normalizedTextColor, + ) + + glyphCount++ + } + x += pixelRatioAdaptedFontWidth + } + + y += pixelRatioAdaptedFontHeight + } + this._atlas.uploadTexture() + + return glyphCount + } + + private drawGlyphInstances(glyphCount: number, viewportScaleX: number, viewportScaleY: number) { + this._gl.bindVertexArray(this._vertexArrayObject) + this._gl.enable(this._gl.BLEND) + + this._gl.useProgram(this._firstPassProgram) + this._gl.uniform2f(this._firstPassViewportScaleLocation, viewportScaleX, viewportScaleY) + this._gl.bindBuffer(this._gl.ARRAY_BUFFER, this._glyphInstancesBuffer) + this._gl.bufferData(this._gl.ARRAY_BUFFER, this._glyphInstances, this._gl.STREAM_DRAW) + this._gl.blendFuncSeparate( + this._gl.ZERO, + this._gl.ONE_MINUS_SRC_COLOR, + this._gl.ZERO, + this._gl.ONE, + ) + this._gl.drawElementsInstanced(this._gl.TRIANGLES, 6, this._gl.UNSIGNED_BYTE, 0, glyphCount) + + this._gl.useProgram(this._secondPassProgram) + this._gl.blendFuncSeparate( + this._gl.ONE, + this._gl.ONE, + this._gl.ONE, + this._gl.ONE_MINUS_SRC_ALPHA, + ) + this._gl.uniform2f(this._secondPassViewportScaleLocation, viewportScaleX, viewportScaleY) + this._gl.drawElementsInstanced(this._gl.TRIANGLES, 6, this._gl.UNSIGNED_BYTE, 0, glyphCount) + } + + private updateGlyphInstance( + index: number, + x: number, + y: number, + glyph: WebGLGlyph, + color: Float32Array, + ) { + const startOffset = glyphInstanceFieldCount * index + // targetOrigin + this._glyphInstances[0 + startOffset] = x + this._glyphInstances[1 + startOffset] = y + // targetSize + this._glyphInstances[2 + startOffset] = glyph.width + this._glyphInstances[3 + startOffset] = glyph.height + // textColorRGBA + this._glyphInstances[4 + startOffset] = color[0] + this._glyphInstances[5 + startOffset] = color[1] + this._glyphInstances[6 + startOffset] = color[2] + this._glyphInstances[7 + startOffset] = color[3] + // atlasOrigin + this._glyphInstances[8 + startOffset] = glyph.textureU + this._glyphInstances[9 + startOffset] = glyph.textureV + // atlasSize + this._glyphInstances[10 + startOffset] = glyph.textureWidth + this._glyphInstances[11 + startOffset] = glyph.textureHeight + } +} diff --git a/browser/src/Renderer/WebGL/WebGLUtilities.ts b/browser/src/Renderer/WebGL/WebGLUtilities.ts new file mode 100644 index 0000000000..ce5cf5f478 --- /dev/null +++ b/browser/src/Renderer/WebGL/WebGLUtilities.ts @@ -0,0 +1,57 @@ +export const createProgram = ( + gl: WebGL2RenderingContext, + vertexShaderSource: string, + fragmentShaderSource: string, +) => { + const vertexShader = compileShader(gl, vertexShaderSource, gl.VERTEX_SHADER) + const fragmentShader = compileShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER) + return linkProgram(gl, vertexShader, fragmentShader) +} + +const compileShader = (gl: WebGL2RenderingContext, source: string, type: number) => { + const shader = gl.createShader(type) + gl.shaderSource(shader, source) + gl.compileShader(shader) + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + const info = gl.getShaderInfoLog(shader) + throw new Error("Could not compile WebGL program: \n\n" + info) + } + + return shader +} + +const linkProgram = ( + gl: WebGL2RenderingContext, + vertexShader: WebGLShader, + fragmentShader: WebGLShader, +) => { + const program = gl.createProgram() + gl.attachShader(program, vertexShader) + gl.attachShader(program, fragmentShader) + gl.linkProgram(program) + + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + const info = gl.getProgramInfoLog(program) + throw new Error("Could not compile WebGL program: \n\n" + info) + } + return program +} + +const unitQuadVertices = new Float32Array([1, 1, 1, 0, 0, 0, 0, 1]) + +export const createUnitQuadVerticesBuffer = (gl: WebGL2RenderingContext) => { + const unitQuadVerticesBuffer = gl.createBuffer() + gl.bindBuffer(gl.ARRAY_BUFFER, unitQuadVerticesBuffer) + gl.bufferData(gl.ARRAY_BUFFER, unitQuadVertices, gl.STATIC_DRAW) + return unitQuadVerticesBuffer +} + +const unitQuadElementIndices = new Uint8Array([0, 1, 3, 1, 2, 3]) + +export const createUnitQuadElementIndicesBuffer = (gl: WebGL2RenderingContext) => { + const unitQuadElementIndicesBuffer = gl.createBuffer() + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, unitQuadElementIndicesBuffer) + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, unitQuadElementIndices, gl.STATIC_DRAW) + return unitQuadElementIndicesBuffer +} diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 9899433c62..f2acbbf3ef 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -82,6 +82,8 @@ const BaseConfiguration: IConfigurationValues = { "oni.exclude": ["node_modules", ".git"], "oni.bookmarks": [], + "editor.renderer": "canvas", + "editor.backgroundOpacity": 1.0, "editor.backgroundImageUrl": null, "editor.backgroundImageSize": "cover", diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index 5f9ec8f431..b515d33454 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -99,6 +99,12 @@ export interface IConfigurationValues { // Editor settings + // Setting this to "webgl" switches to the experimental + // WebGL-based renderer. Please be aware that this might + // lead to instability or unexpected behavior until it is + // considered stable. + "editor.renderer": "canvas" | "webgl" + "editor.backgroundOpacity": number "editor.backgroundImageUrl": string "editor.backgroundImageSize": string diff --git a/browser/src/color-normalize.d.ts b/browser/src/color-normalize.d.ts new file mode 100644 index 0000000000..6c9bec5011 --- /dev/null +++ b/browser/src/color-normalize.d.ts @@ -0,0 +1,29 @@ +type ColorInput = + | string + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Float32Array + | Float64Array + | Array + | Uint8ClampedArray + +declare module "color-normalize" { + export function call(thisArg: any, color: ColorInput, type: "float"): float[] + export function call(thisArg: any, color: ColorInput, type: "array"): float[] + export function call(thisArg: any, color: ColorInput, type: "int8"): Int8Array + export function call(thisArg: any, color: ColorInput, type: "int16"): Int8Array + export function call(thisArg: any, color: ColorInput, type: "int32"): Int8Array + export function call(thisArg: any, color: ColorInput, type: "uint"): Uint8Array + export function call(thisArg: any, color: ColorInput, type: "uint8"): Uint8Array + export function call(thisArg: any, color: ColorInput, type: "uint16"): Uint8Array + export function call(thisArg: any, color: ColorInput, type: "uint32"): Uint8Array + export function call(thisArg: any, color: ColorInput, type: "float32"): Float32Array + export function call(thisArg: any, color: ColorInput, type: "float64"): Float64Array + export function call(thisArg: any, color: ColorInput, type: "uint_clamped"): Uint8ClampedArray + export function call(thisArg: any, color: ColorInput, type: "uint8_clamped"): Uint8ClampedArray + export function call(thisArg: any, color: ColorInput): float[] +} diff --git a/browser/src/neovim/Screen.ts b/browser/src/neovim/Screen.ts index ff434c4955..7fe7642741 100644 --- a/browser/src/neovim/Screen.ts +++ b/browser/src/neovim/Screen.ts @@ -149,7 +149,7 @@ export class NeovimScreen implements IScreen { return this._currentHighlight.backgroundColor || this._backgroundColor } - public getCell(x: number, y: number): ICell { + public getCell = (x: number, y: number) => { const cell = this._grid.getCell(x, y) if (cell) { diff --git a/browser/tsconfig.json b/browser/tsconfig.json index 92817ac4d9..d8157e6cc0 100644 --- a/browser/tsconfig.json +++ b/browser/tsconfig.json @@ -24,7 +24,7 @@ "suppressImplicitAnyIndexErrors": true, "target": "es2015", "sourceMap": true, - "types": ["mocha"] + "types": ["mocha", "webgl2"] }, "include": ["src/**/*.ts", "test/**/*.ts"], "exclude": ["node_modules"] diff --git a/browser/tsconfig.test.json b/browser/tsconfig.test.json index 0174601759..f2488b6c90 100644 --- a/browser/tsconfig.test.json +++ b/browser/tsconfig.test.json @@ -20,7 +20,7 @@ "suppressImplicitAnyIndexErrors": true, "target": "es2015", "sourceMap": true, - "types": ["mocha"] + "types": ["mocha", "webgl2"] }, "include": ["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts"], "exclude": ["node_modules"] diff --git a/package.json b/package.json index d9a12ff841..b8078a828e 100644 --- a/package.json +++ b/package.json @@ -687,6 +687,7 @@ "license": "MIT", "dependencies": { "chokidar": "^2.0.3", + "color-normalize": "^1.0.3", "dompurify": "^1.0.3", "electron-settings": "^3.1.4", "find-up": "2.1.0", @@ -749,6 +750,7 @@ "@types/rimraf": "^2.0.2", "@types/shelljs": "^0.7.7", "@types/sinon": "1.16.32", + "@types/webgl2": "^0.0.3", "autoprefixer": "6.4.0", "aws-sdk": "^2.202.0", "azure-storage": "^2.8.1", diff --git a/ui-tests/tsconfig.react.json b/ui-tests/tsconfig.react.json index b28da3b597..3621a32087 100644 --- a/ui-tests/tsconfig.react.json +++ b/ui-tests/tsconfig.react.json @@ -20,7 +20,7 @@ "suppressImplicitAnyIndexErrors": true, "target": "es2015", "sourceMap": true, - "types": ["jest", "electron", "react"] + "types": ["jest", "electron", "react", "webgl2"] }, "include": ["**/*.tsx", "**/*.ts", "../browser/**/*.ts", "../browser/**/*.tsx"], "exclude": ["node_modules"] diff --git a/yarn.lock b/yarn.lock index e8598887cb..99590d45cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -261,6 +261,10 @@ version "2.3.2" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.2.tgz#e0d481d8bb282ad8a8c9e100ceb72c995fb5e709" +"@types/webgl2@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/webgl2/-/webgl2-0.0.3.tgz#51d51a60dc61addcef083ec69535bfc980cda238" + abab@^1.0.3, abab@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" @@ -362,6 +366,10 @@ align-text@^0.1.1, align-text@^0.1.3: longest "^1.0.1" repeat-string "^1.5.2" +almost-equal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/almost-equal/-/almost-equal-1.1.0.tgz#f851c631138757994276aa2efbe8dfa3066cccdd" + alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -748,11 +756,12 @@ autoprefixer@^6.0.0, autoprefixer@^6.3.1: postcss-value-parser "^3.2.3" aws-sdk@^2.202.0: - version "2.202.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.202.0.tgz#c1bd90c1dc0bfe835522fe81f29cf8bb71bf00cc" + version "2.226.1" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.226.1.tgz#8e6e2b466aaf26cb35714905d5f934e6c8317a99" dependencies: buffer "4.9.1" - events "^1.1.1" + events "1.1.1" + ieee754 "1.1.8" jmespath "0.15.0" querystring "0.2.0" sax "1.2.1" @@ -2211,6 +2220,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +clamp@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/clamp/-/clamp-1.0.1.tgz#66a0e64011816e37196828fdc8c8c147312c8634" + clap@^1.0.9: version "1.2.3" resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" @@ -2231,8 +2244,8 @@ classnames@2.2.5, classnames@^2.2.3, classnames@^2.2.5: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" clean-css@4.1.x: - version "4.1.9" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.9.tgz#35cee8ae7687a49b98034f70de00c4edd3826301" + version "4.1.11" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.11.tgz#2ecdf145aba38f54740f26cefd0ff3e03e125d6a" dependencies: source-map "0.5.x" @@ -2382,6 +2395,37 @@ color-name@^1.0.0, color-name@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" +color-normalize@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/color-normalize/-/color-normalize-1.0.3.tgz#9d718a2aefccf20c5f75d87c4322f30c672b2639" + dependencies: + clamp "^1.0.1" + color-rgba "^2.0.0" + dtype "^2.0.0" + +color-parse@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/color-parse/-/color-parse-1.3.5.tgz#4c810f72e808e4f73b63f72acd78da538a515564" + dependencies: + color-name "^1.0.0" + defined "^1.0.0" + is-plain-obj "^1.1.0" + +color-rgba@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/color-rgba/-/color-rgba-2.0.0.tgz#d015114ce3e84368795c9d6ddfef556f981739c5" + dependencies: + clamp "^1.0.1" + color-parse "^1.3.5" + color-space "^1.14.6" + +color-space@^1.14.6: + version "1.16.0" + resolved "https://registry.yarnpkg.com/color-space/-/color-space-1.16.0.tgz#611781bca41cd8582a1466fd9e28a7d3d89772a2" + dependencies: + hsluv "^0.0.3" + mumath "^3.3.4" + color-string@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" @@ -2440,9 +2484,9 @@ commander@2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" -commander@2.14.x, commander@~2.14.1: - version "2.14.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" +commander@2.15.x, commander@^2.13.0, commander@~2.15.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" commander@2.6.0: version "2.6.0" @@ -2462,10 +2506,6 @@ commander@^2.12.1, commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" -commander@^2.13.0: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -3250,6 +3290,10 @@ dotenv@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" +dtype@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dtype/-/dtype-2.0.0.tgz#cd052323ce061444ecd2e8f5748f69a29be28434" + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -3282,8 +3326,8 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" ejs@^2.3.1: - version "2.5.8" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.8.tgz#2ab6954619f225e6193b7ac5f7c39c48fefe4380" + version "2.5.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" ejs@^2.5.7, ejs@~2.5.6: version "2.5.7" @@ -3724,7 +3768,7 @@ eventemitter3@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" -events@^1.0.0, events@^1.1.1: +events@1.1.1, events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -4802,6 +4846,10 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" +hsluv@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/hsluv/-/hsluv-0.0.3.tgz#829107dafb4a9f8b52a1809ed02e091eade6754c" + html-comment-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" @@ -4827,14 +4875,13 @@ html-loader@^0.5.5: object-assign "^4.1.1" html-minifier@^3.5.8: - version "3.5.9" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.9.tgz#74424014b872598d4bb0e20ac420926ec61024b6" + version "3.5.15" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.15.tgz#f869848d4543cbfd84f26d5514a2a87cbf9a05e0" dependencies: camel-case "3.0.x" clean-css "4.1.x" - commander "2.14.x" + commander "2.15.x" he "1.1.x" - ncname "1.0.x" param-case "2.1.x" relateurl "0.2.x" uglify-js "3.3.x" @@ -4929,7 +4976,7 @@ icss-utils@^2.1.0: dependencies: postcss "^6.0.1" -ieee754@^1.1.4, ieee754@^1.1.8: +ieee754@1.1.8, ieee754@^1.1.4, ieee754@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" @@ -6833,6 +6880,12 @@ multimatch@^2.0.0: arrify "^1.0.0" minimatch "^3.0.0" +mumath@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/mumath/-/mumath-3.3.4.tgz#48d4a0f0fd8cad4e7b32096ee89b161a63d30bbf" + dependencies: + almost-equal "^1.1.0" + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -6862,12 +6915,6 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -ncname@1.0.x: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c" - dependencies: - xml-char-classes "^1.0.0" - nearley@^2.7.10: version "2.11.1" resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.11.1.tgz#a9c0a5fa942998db5ad18b14fbc8e9fc49672f16" @@ -8244,15 +8291,20 @@ react-dom@16.0.0: prop-types "^15.6.0" react-hot-loader@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.0.1.tgz#48284350ae5d7ba07dac872bd5bbc6e477352593" + version "4.1.0" + resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.1.0.tgz#ae47224af27981c02d4b8c61d498e89d6d207096" dependencies: fast-levenshtein "^2.0.6" global "^4.3.0" hoist-non-react-statics "^2.5.0" prop-types "^15.6.1" + react-lifecycles-compat "^2.0.0" shallowequal "^1.0.2" +react-lifecycles-compat@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-2.0.2.tgz#00a23160eec17a43b94dd74f95d44a1a2c3c5ec1" + react-motion@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.5.2.tgz#0dd3a69e411316567927917c6626551ba0607316" @@ -8994,8 +9046,8 @@ send@0.16.2: statuses "~1.4.0" serialize-javascript@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" + version "1.5.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" serve-index@^1.7.2: version "1.9.1" @@ -10004,10 +10056,10 @@ uglify-es@^3.3.4: source-map "~0.6.1" uglify-js@3.3.x: - version "3.3.12" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.12.tgz#efd87c16a1f4c674a8a5ede571001ef634dcc883" + version "3.3.22" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.22.tgz#e5f0e50ddd386b7e35b728b51600bf7a7ad0b0dc" dependencies: - commander "~2.14.1" + commander "~2.15.0" source-map "~0.6.1" uglify-js@^2.6: @@ -10024,8 +10076,8 @@ uglify-to-browserify@~1.0.0: resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" uglifyjs-webpack-plugin@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.4.tgz#5eec941b2e9b8538be0a20fc6eda25b14c7c1043" + version "1.2.5" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz#2ef8387c8f1a903ec5e44fa36f9f3cbdcea67641" dependencies: cacache "^10.0.4" find-cache-dir "^1.0.0" @@ -10784,10 +10836,6 @@ xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" -xml-char-classes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" - xml-name-validator@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" From 6bc376beb6c504c1b63115cf916b9d469a73d9a5 Mon Sep 17 00:00:00 2001 From: Akin <akin.sowemimo@gmail.com> Date: Wed, 25 Apr 2018 07:42:31 +0100 Subject: [PATCH 54/59] Feature/add new file in explorer (#2130) * add initial implementation of creating node * merge rename functionality into new file branch * add create folder and file commands and methods add input block and activation of vim navigator block * add undo functionality for creation * fix lint errors * update snapshot; * add unit tests for filesystem and tests for epic * add test check that node creation can be undone * if target is folder create new file or folder *INSIDE* the target * expand dir if new file or folder created inside * remove trailing slash in test expectations * move input for new node to appear below the selected node --- browser/src/Input/KeyBindings.ts | 2 + .../Services/Explorer/ExplorerFileSystem.ts | 37 ++-- .../src/Services/Explorer/ExplorerSplit.tsx | 64 ++++-- .../src/Services/Explorer/ExplorerStore.ts | 183 +++++++++++++++--- .../src/Services/Explorer/ExplorerView.tsx | 39 +++- .../Explorer/ExplorerFileSystemTests.ts | 43 +++- .../Services/Explorer/ExplorerStoreTests.ts | 104 ++++++++++ ui-tests/__snapshots__/NodeView.test.tsx.snap | 44 +++-- 8 files changed, 428 insertions(+), 88 deletions(-) diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index efdb8e6aac..accdc455b9 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -142,6 +142,8 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind("h", "explorer.collapse.directory", isExplorerActive) input.bind("l", "explorer.expand.directory", isExplorerActive) input.bind("r", "explorer.rename", isExplorerActive) + input.bind("<c-e>", "explorer.create.file", isExplorerActive) + input.bind("<c-f>", "explorer.create.folder", isExplorerActive) // Browser input.bind("k", "browser.scrollUp") diff --git a/browser/src/Services/Explorer/ExplorerFileSystem.ts b/browser/src/Services/Explorer/ExplorerFileSystem.ts index f8dc5cd74f..7ad60071e7 100644 --- a/browser/src/Services/Explorer/ExplorerFileSystem.ts +++ b/browser/src/Services/Explorer/ExplorerFileSystem.ts @@ -5,12 +5,11 @@ */ import * as fs from "fs" -import { emptyDirSync, ensureDirSync, move, remove } from "fs-extra" +import { emptyDirSync, ensureDirSync, mkdirp, move, pathExists, remove, writeFile } from "fs-extra" import * as os from "os" import * as path from "path" import { promisify } from "util" -import { ExplorerNode } from "./ExplorerSelectors" import { FolderOrFile } from "./ExplorerStore" /** @@ -21,10 +20,12 @@ export interface IFileSystem { exists(fullPath: string): Promise<boolean> persistNode(fullPath: string): Promise<void> restoreNode(fullPath: string): Promise<void> - deleteNode(node: ExplorerNode): Promise<void> + deleteNode(fullPath: string): Promise<void> canPersistNode(fullPath: string, size: number): Promise<boolean> move(source: string, dest: string): Promise<void> moveNodesBack(collection: Array<{ source: string; destination: string }>): Promise<void> + writeFile(filepath: string): Promise<void> + mkdir(folderpath: string): Promise<void> } export class FileSystem implements IFileSystem { @@ -88,17 +89,8 @@ export class FileSystem implements IFileSystem { * @function * @param {ExplorerNode} node The file or folder node */ - public deleteNode = async (node: ExplorerNode): Promise<void> => { - switch (node.type) { - case "folder": - await remove(node.folderPath) - break - case "file": - await remove(node.filePath) - break - default: - break - } + public async deleteNode(fullPath: string): Promise<void> { + await remove(fullPath) } /** @@ -162,6 +154,23 @@ export class FileSystem implements IFileSystem { return size < maxSize } + /** + * createFile + */ + public async writeFile(filepath: string) { + if (await pathExists(filepath)) { + throw new Error("This path already exists") + } + await writeFile(filepath, "", null) + } + + public async mkdir(folderpath: string) { + if (await pathExists(folderpath)) { + throw new Error("This path already exists") + } + await mkdirp(folderpath) + } + private areDifferent = (src: string, dest: string) => src !== dest } diff --git a/browser/src/Services/Explorer/ExplorerSplit.tsx b/browser/src/Services/Explorer/ExplorerSplit.tsx index c6939aa398..b42a7e170f 100644 --- a/browser/src/Services/Explorer/ExplorerSplit.tsx +++ b/browser/src/Services/Explorer/ExplorerSplit.tsx @@ -17,7 +17,7 @@ import { getInstance as NotificationsInstance } from "./../../Services/Notificat import { windowManager } from "./../../Services/WindowManager" import { IWorkspace } from "./../../Services/Workspace" -import { createStore, IExplorerState } from "./ExplorerStore" +import { createStore, getPathForNode, IExplorerState } from "./ExplorerStore" import * as ExplorerSelectors from "./ExplorerSelectors" import { Explorer } from "./ExplorerView" @@ -92,6 +92,8 @@ export class ExplorerSplit { return ( <Provider store={this._store}> <Explorer + onCancelCreate={this._cancelCreation} + onCompleteCreate={this._completeCreation} onCompleteRename={this._completeRename} onCancelRename={this._cancelRename} onSelectionChanged={id => this._onSelectionChanged(id)} @@ -102,9 +104,9 @@ export class ExplorerSplit { ) } - private _isRenaming = () => { - const { register: { rename } } = this._store.getState() - return rename.active + private _inputInProgress = () => { + const { register: { rename, create } } = this._store.getState() + return rename.active || create.active } private _initialiseExplorerCommands(): void { @@ -113,7 +115,7 @@ export class ExplorerSplit { "explorer.delete.persist", null, null, - () => !this._isRenaming() && this._onDeleteItem({ persist: true }), + () => !this._inputInProgress() && this._onDeleteItem({ persist: true }), ), ) this._commandManager.registerCommand( @@ -121,7 +123,7 @@ export class ExplorerSplit { "explorer.delete", null, null, - () => !this._isRenaming() && this._onDeleteItem({ persist: false }), + () => !this._inputInProgress() && this._onDeleteItem({ persist: false }), ), ) this._commandManager.registerCommand( @@ -129,7 +131,7 @@ export class ExplorerSplit { "explorer.yank", "Yank Selected Item", "Select a file to move", - () => !this._isRenaming() && this._onYankItem(), + () => !this._inputInProgress() && this._onYankItem(), ), ) @@ -138,7 +140,7 @@ export class ExplorerSplit { "explorer.undo", "Undo last explorer action", null, - () => !this._isRenaming() && this._onUndoItem(), + () => !this._inputInProgress() && this._onUndoItem(), ), ) @@ -147,7 +149,25 @@ export class ExplorerSplit { "explorer.paste", "Move/Paste Selected Item", "Paste the last yanked item", - () => !this._isRenaming() && this._onPasteItem(), + () => !this._inputInProgress() && this._onPasteItem(), + ), + ) + + this._commandManager.registerCommand( + new CallbackCommand( + "explorer.create.file", + "Create A New File in the Explorer", + null, + () => !this._inputInProgress() && this._onCreateNode({ type: "file" }), + ), + ) + + this._commandManager.registerCommand( + new CallbackCommand( + "explorer.create.folder", + "Create A New File in the Explorer", + null, + () => !this._inputInProgress() && this._onCreateNode({ type: "folder" }), ), ) @@ -156,7 +176,7 @@ export class ExplorerSplit { "explorer.expand.directory", "Expand a selected directory", null, - () => !this._isRenaming() && this._toggleDirectory("expand"), + () => !this._inputInProgress() && this._toggleDirectory("expand"), ), ) @@ -165,7 +185,7 @@ export class ExplorerSplit { "explorer.collapse.directory", "Collapse selected directory", null, - () => !this._isRenaming() && this._toggleDirectory("collapse"), + () => !this._inputInProgress() && this._toggleDirectory("collapse"), ), ) @@ -174,7 +194,7 @@ export class ExplorerSplit { "explorer.rename", "Rename the selected file/folder", null, - () => !this._isRenaming() && this._renameItem(), + () => !this._inputInProgress() && this._renameItem(), ), ) } @@ -263,6 +283,26 @@ export class ExplorerSplit { this._store.dispatch({ type: "RENAME_CANCEL" }) } + private _onCreateNode = ({ type }: { type: "file" | "folder" }) => { + this._store.dispatch({ type: "CREATE_NODE_START", nodeType: type }) + } + + private _completeCreation = (newName: string) => { + const target = this._getSelectedItem() + + if (!target) { + return + } + + const nodePath = getPathForNode(target) + const dirname = target.type === "file" ? path.dirname(nodePath) : nodePath + this._store.dispatch({ type: "CREATE_NODE_COMMIT", name: path.join(dirname, newName) }) + } + + private _cancelCreation = () => { + this._store.dispatch({ type: "CREATE_NODE_CANCEL" }) + } + // This is different from on openItem since it only activates if the target is a folder // also it means that each bound key only does one thing aka "h" collapses and "l" // expands they are not toggles diff --git a/browser/src/Services/Explorer/ExplorerStore.ts b/browser/src/Services/Explorer/ExplorerStore.ts index deb78bf340..e522b86792 100644 --- a/browser/src/Services/Explorer/ExplorerStore.ts +++ b/browser/src/Services/Explorer/ExplorerStore.ts @@ -41,6 +41,11 @@ export const DefaultRegisterState: IRegisterState = { undo: [], paste: EmptyNode, updated: null, + create: { + active: false, + name: null, + nodeType: null, + }, rename: { active: false, target: null, @@ -77,6 +82,8 @@ export type RegisterAction = | IUndoFailAction | IRenameSuccessAction | IRenameFailAction + | ICreateNodeSuccessAction + | ICreateNodeFailAction interface IRegisterState { yank: ExplorerNode[] @@ -87,6 +94,11 @@ interface IRegisterState { target: ExplorerNode } updated: string[] + create: { + active: boolean + name: string + nodeType: "file" | "folder" + } } export interface IExplorerState { @@ -196,6 +208,31 @@ export interface IClearUpdateAction { type: "CLEAR_UPDATE" } +export interface ICreateNodeStartAction { + type: "CREATE_NODE_START" + nodeType: "file" | "folder" +} + +export interface ICreateNodeCancelAction { + type: "CREATE_NODE_CANCEL" +} + +export interface ICreateNodeCommitAction { + type: "CREATE_NODE_COMMIT" + name: string +} + +export interface ICreateNodeFailAction { + type: "CREATE_NODE_FAIL" + reason: string +} + +export interface ICreateNodeSuccessAction { + type: "CREATE_NODE_SUCCESS" + nodeType: "file" | "folder" + name: string +} + export interface IPasteSuccessAction { type: "PASTE_SUCCESS" moved: IMovedNodes[] @@ -264,6 +301,11 @@ export type ExplorerAction = | IUndoAction | IUndoSuccessAction | IUndoFailAction + | ICreateNodeStartAction + | ICreateNodeFailAction + | ICreateNodeCancelAction + | ICreateNodeCommitAction + | ICreateNodeSuccessAction | INotificationSentAction // Helper functions for Updating state ======================================================== @@ -288,6 +330,7 @@ type Updates = | IDeleteSuccessAction | IUndoSuccessAction | IRenameSuccessAction + | ICreateNodeSuccessAction export const getUpdatedNode = (action: Updates, state?: IRegisterState): string[] => { switch (action.type) { @@ -297,6 +340,8 @@ export const getUpdatedNode = (action: Updates, state?: IRegisterState): string[ return [getPathForNode(action.target)] case "RENAME_SUCCESS": return [action.destination] + case "CREATE_NODE_SUCCESS": + return [action.name] case "UNDO_SUCCESS": const lastAction = last(state.undo) @@ -336,6 +381,12 @@ export const getPathForNode = (node: ExplorerNode) => { const Actions = { Null: { type: null } as ExplorerAction, + createNode: (args: { nodeType: "file" | "folder"; name: string }) => + ({ type: "CREATE_NODE_SUCCESS", ...args } as ICreateNodeSuccessAction), + + createNodeFail: (reason: string) => + ({ type: "CREATE_NODE_FAIL", reason } as ICreateNodeFailAction), + pasteSuccess: (moved: IMovedNodes[]) => ({ type: "PASTE_SUCCESS", moved } as IPasteSuccessAction), @@ -345,15 +396,14 @@ const Actions = { undoSuccess: { type: "UNDO_SUCCESS" } as IUndoSuccessAction, - renameSuccess: ({ - source, - destination, - targetType, - }: { + renameSuccess: (args: { source: string destination: string targetType: string - }) => ({ type: "RENAME_SUCCESS", destination, source, targetType } as IRenameSuccessAction), + }): IRenameSuccessAction => ({ + type: "RENAME_SUCCESS", + ...args, + }), renameFail: (reason: string) => ({ type: "RENAME_FAIL", reason } as IRenameFailAction), @@ -409,6 +459,36 @@ export const yankRegisterReducer: Reducer<IRegisterState> = ( action: ExplorerAction, ) => { switch (action.type) { + case "CREATE_NODE_START": + return { + ...state, + create: { + active: true, + name: null, + nodeType: action.nodeType, + }, + } + case "CREATE_NODE_FAIL": + case "CREATE_NODE_CANCEL": + return { + ...state, + create: { + active: false, + name: null, + nodeType: null, + }, + } + case "CREATE_NODE_SUCCESS": + return { + ...state, + create: { + active: false, + name: null, + nodeType: null, + }, + updated: getUpdatedNode(action), + undo: [...state.undo, action], + } case "RENAME_START": return { ...state, @@ -582,7 +662,7 @@ const sendExplorerNotification = ( const notification = notifications.createItem() notification.setContents(title, details) notification.setLevel(level) - notification.setExpiration(8000) + notification.setExpiration(5_000) notification.show() } @@ -635,6 +715,21 @@ const renameNotification = ({ notifications, ) +interface CreationNotificationArgs { + notifications: Notifications + type: "file" | "folder" + name: string +} + +const creationNotification = ({ notifications, type, name }: CreationNotificationArgs): void => + sendExplorerNotification( + { + title: `${capitalize(type)} created successfully`, + details: `${name} created`, + }, + notifications, + ) + interface ErrorNotificationArgs { type: string reason: string @@ -685,12 +780,25 @@ export const pasteEpic: ExplorerEpic = (action$, store, { fileSystem }) => }) }) -const successActions = (maybeDirsNodes: ExplorerNode[]) => [ +const successActions = (maybeDirsNodes: ExplorerNode[] = []) => [ Actions.undoSuccess, ...shouldExpandDirectory(maybeDirsNodes), Actions.refresh, ] +const persistOrDeleteNode = async ( + filepath: string, + fileSystem: IFileSystem, + persist = true, +): Promise<void> => { + const maxSize = configuration.getValue("explorer.maxUndoFileSizeInBytes") + const persistEnabled = configuration.getValue("explorer.persistDeletedFiles") + const canPersistNode = await fileSystem.canPersistNode(filepath, maxSize) + persistEnabled && persist && canPersistNode + ? await fileSystem.persistNode(filepath) + : await fileSystem.deleteNode(filepath) +} + export const undoEpic: ExplorerEpic = (action$, store, { fileSystem }) => action$.ofType("UNDO").mergeMap(action => { const { register: { undo } } = store.getState() @@ -721,11 +829,23 @@ export const undoEpic: ExplorerEpic = (action$, store, { fileSystem }) => case "RENAME_SUCCESS": const { source, destination } = lastAction return fromPromise(fileSystem.move(destination, source)) - .flatMap(() => successActions([])) + .flatMap(() => successActions()) .catch(error => { Log.warn(error) return [Actions.undoFail("The last rename could not be undone, sorry")] }) + + case "CREATE_NODE_SUCCESS": + return fromPromise(persistOrDeleteNode(lastAction.name, fileSystem)) + .flatMap(() => successActions()) + .catch(error => { + Log.warn(error) + return [ + Actions.undoFail( + "The last file/folder creation could not be undone, sorry", + ), + ] + }) default: return [Actions.undoFail("Sorry we can't undo the last action")] } @@ -735,22 +855,13 @@ export const deleteEpic: ExplorerEpic = (action$, store, { fileSystem }) => action$.ofType("DELETE").mergeMap((action: IDeleteAction) => { const { target, persist } = action const filepath = getPathForNode(target) - const maxSize = configuration.getValue("explorer.maxUndoFileSizeInBytes") - const persistEnabled = configuration.getValue("explorer.persistDeletedFiles") - const persistPromise = fileSystem.canPersistNode(filepath, maxSize) - - return fromPromise(persistPromise).flatMap(canPersistNode => - fromPromise( - persistEnabled && persist && canPersistNode - ? fileSystem.persistNode(filepath) - : fileSystem.deleteNode(target), - ) - .flatMap(() => [Actions.deleteSuccess(target, persist), Actions.refresh]) - .catch(error => { - Log.warn(error) - return [Actions.deleteFail(error.message)] - }), - ) + + return fromPromise(persistOrDeleteNode(filepath, fileSystem, persist)) + .flatMap(() => [Actions.deleteSuccess(target, persist), Actions.refresh]) + .catch(error => { + Log.warn(error) + return [Actions.deleteFail(error.message)] + }) }) export const renameEpic: ExplorerEpic = (action$, store, { fileSystem }) => @@ -806,15 +917,28 @@ const expandDirectoryEpic: ExplorerEpic = (action$, store, { fileSystem }) => return Actions.expandDirectoryResult(pathToExpand, sortedFilesAndFolders) }) +export const createNodeEpic: ExplorerEpic = (action$, store, { fileSystem }) => + action$.ofType("CREATE_NODE_COMMIT").mergeMap(({ name }: ICreateNodeCommitAction) => { + const { register: { create: { nodeType } } } = store.getState() + const shouldExpand = Actions.expandDirectory(path.dirname(name)) + const createFileOrFolder = + nodeType === "file" ? fileSystem.writeFile(name) : fileSystem.mkdir(name) + return fromPromise(createFileOrFolder) + .flatMap(() => [Actions.createNode({ nodeType, name }), shouldExpand, Actions.refresh]) + .catch(error => [Actions.createNodeFail(error.message)]) + }) + export const notificationEpic: ExplorerEpic = (action$, store, { notifications }) => action$ .ofType( "PASTE_SUCCESS", "DELETE_SUCCESS", "RENAME_SUCCESS", + "CREATE_NODE_SUCCESS", "RENAME_FAIL", "PASTE_FAIL", "DELETE_FAIL", + "CREATE_NODE_FAIL", ) .map(action => { switch (action.type) { @@ -843,9 +967,17 @@ export const notificationEpic: ExplorerEpic = (action$, store, { notifications } destination: action.destination, }) return Actions.notificationSent(action.type) + case "CREATE_NODE_SUCCESS": + creationNotification({ + notifications, + type: action.nodeType, + name: action.name, + }) + return Actions.notificationSent(action.type) case "PASTE_FAIL": case "DELETE_FAIL": case "RENAME_FAIL": + case "CREATE_NODE_FAIL": const [type] = action.type.split("_") errorNotification({ type, @@ -872,6 +1004,7 @@ export const createStore = ({ combineEpics( refreshEpic, setRootDirectoryEpic, + createNodeEpic, clearUpdateEpic, clearYankRegisterEpic, renameEpic, diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index 747b492e53..0a656e39fa 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -32,9 +32,12 @@ export interface INodeViewProps { onClick: () => void onCancelRename: () => void onCompleteRename: (newName: string) => void + onCancelCreate?: () => void + onCompleteCreate?: (path: string) => void yanked: string[] updated?: string[] isRenaming: Node + isCreating: boolean } export const NodeWrapper = styled.div` @@ -103,11 +106,16 @@ const renameStyles = css` color: inherit; font-size: inherit; font-family: inherit; - padding: 0.5rem; + padding: 0.5em; box-sizing: border-box; border: 2px solid ${p => p.theme["highlight.mode.normal.background"]} !important; ` +const createStyles = css` + ${renameStyles}; + margin-top: 0.2em; +` + export class NodeView extends React.PureComponent<INodeViewProps, {}> { public moveFileOrFolder = ({ drag, drop }: IMoveNode) => { this.props.moveFileOrFolder(drag.node, drop.node) @@ -118,8 +126,9 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { } public render(): JSX.Element { - const { isRenaming, isSelected, node } = this.props - const renameInProgress = isRenaming.name === node.name && isSelected + const { isCreating, isRenaming, isSelected, node } = this.props + const renameInProgress = isRenaming.name === node.name && isSelected && !isCreating + const creationInProgress = isCreating && isSelected && !renameInProgress return ( <NodeWrapper style={{ cursor: "pointer" }} @@ -132,7 +141,16 @@ export class NodeView extends React.PureComponent<INodeViewProps, {}> { onComplete={this.props.onCompleteRename} /> ) : ( - this.getElement() + <div> + {this.getElement()} + {creationInProgress && ( + <TextInputView + styles={createStyles} + onCancel={this.props.onCancelCreate} + onComplete={this.props.onCompleteCreate} + /> + )} + </div> )} </NodeWrapper> ) @@ -239,7 +257,10 @@ export interface IExplorerViewContainerProps { onCancelRename: () => void onCompleteRename: (newName: string) => void yanked?: string[] + isCreating?: boolean isRenaming?: Node + onCancelCreate?: () => void + onCompleteCreate?: (path: string) => void } export interface IExplorerViewProps extends IExplorerViewContainerProps { @@ -271,21 +292,24 @@ export class ExplorerView extends React.PureComponent<IExplorerViewProps, {}> { <TransitionGroup> <VimNavigator ids={ids} - active={this.props.isActive && !this.props.isRenaming} + active={this.props.isActive && !this.props.isRenaming && !this.props.isCreating} onSelectionChanged={this.props.onSelectionChanged} onSelected={id => this.props.onClick(id)} render={(selectedId: string) => { const nodes = this.props.nodes.map(node => ( <Sneakable callback={() => this.props.onClick(node.id)} key={node.id}> <NodeView + node={node} + isSelected={node.id === selectedId} + isCreating={this.props.isCreating} + onCancelCreate={this.props.onCancelCreate} + onCompleteCreate={this.props.onCompleteCreate} onCompleteRename={this.props.onCompleteRename} isRenaming={this.props.isRenaming} onCancelRename={this.props.onCancelRename} updated={this.props.updated} yanked={this.props.yanked} moveFileOrFolder={this.props.moveFileOrFolder} - node={node} - isSelected={node.id === selectedId} onClick={() => this.props.onClick(node.id)} /> </Sneakable> @@ -315,6 +339,7 @@ const mapStateToProps = ( nodes: ExplorerSelectors.mapStateToNodeList(state), updated, yanked, + isCreating: state.register.create.active, isRenaming: rename.active && rename.target, } } diff --git a/browser/test/Services/Explorer/ExplorerFileSystemTests.ts b/browser/test/Services/Explorer/ExplorerFileSystemTests.ts index 0255214c43..15daaa1cd7 100644 --- a/browser/test/Services/Explorer/ExplorerFileSystemTests.ts +++ b/browser/test/Services/Explorer/ExplorerFileSystemTests.ts @@ -1,5 +1,5 @@ import * as assert from "assert" -import { emptyDir, mkdirp, remove, stat, writeFile } from "fs-extra" +import { emptyDir, mkdirp, pathExists, remove, stat, writeFile } from "fs-extra" import * as os from "os" import * as path from "path" @@ -40,14 +40,7 @@ describe("File System tests", async () => { assert.ok(canPersist) }) it("Should delete the file", async () => { - await fileSystem.deleteNode({ - filePath: secondPath, - id: "2", - type: "file", - modified: false, - name: "file1", - indentationLevel: 2, - }) + await fileSystem.deleteNode(secondPath) try { await stat(secondPath) } catch (e) { @@ -74,4 +67,36 @@ describe("File System tests", async () => { assert.ok(firstStats.isFile()) assert.ok(secondStats.isFile()) }) + + it("Should create a new file", async () => { + const newPath = path.join(rootPath, "created.txt") + await fileSystem.writeFile(newPath) + const created = await pathExists(newPath) + assert.ok(created) + }) + + it("Should throw an error if the filepath already exists", async () => { + try { + await fileSystem.writeFile(filePath) + } catch (e) { + assert.ok(!!e) + assert.ok(e.message === "This path already exists") + } + }) + + it("Should create a new folder", async () => { + const newPath = path.join(rootPath, "new_dir") + await fileSystem.writeFile(newPath) + const created = await pathExists(newPath) + assert.ok(created) + }) + + it("Should throw an error if the folderpath already exists", async () => { + try { + await fileSystem.mkdir(rootPath) + } catch (e) { + assert.ok(!!e) + assert.ok(e.message === "This path already exists") + } + }) }) diff --git a/browser/test/Services/Explorer/ExplorerStoreTests.ts b/browser/test/Services/Explorer/ExplorerStoreTests.ts index 196efb0658..42efa76420 100644 --- a/browser/test/Services/Explorer/ExplorerStoreTests.ts +++ b/browser/test/Services/Explorer/ExplorerStoreTests.ts @@ -49,6 +49,8 @@ export class MockedFileSystem implements ExplorerFileSystem.IFileSystem { public async moveNodesBack(): Promise<void> {} public async deleteNode(): Promise<void> {} public async move(source: string, destination: string): Promise<void> {} + public async writeFile(name: string): Promise<void> {} + public async mkdir(name: string): Promise<void> {} // tslint:enable } @@ -158,6 +160,8 @@ describe("ExplorerStore", () => { deleteNode: file => null, canPersistNode: async (file, size) => true, moveNodesBack: async collection => null, + writeFile: async name => null, + mkdir: async name => null, } as ExplorerFileSystem.IFileSystem const notifications = { @@ -461,6 +465,106 @@ describe("ExplorerStore", () => { .toArray() .subscribe(actualAction => assert.deepEqual(actualAction, expected)) }) + + it("Should return a create node success action if a creation is committed", () => { + const action$ = ActionsObservable.of({ + type: "CREATE_NODE_COMMIT", + name: "/test/dir/file.txt", + } as ExplorerState.ICreateNodeCommitAction) + + const stateCopy = clone(ExplorerState.DefaultExplorerState) + const state = { + ...stateCopy, + register: { + ...stateCopy.register, + create: { + active: true, + nodeType: "file" as "file" | "folder", + name: "/test/dir/file.txt", + }, + }, + } + + const createState = mockStore(state) + + const expected = [ + { type: "CREATE_NODE_SUCCESS", nodeType: "file", name: "/test/dir/file.txt" }, + { type: "EXPAND_DIRECTORY", directoryPath: "/test/dir" }, + { type: "REFRESH" }, + ] + + ExplorerState.createNodeEpic(action$, createState, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualActions => assert.deepEqual(actualActions, expected)) + }) + + it("Should return an error action if a creation fails", () => { + const action$ = ActionsObservable.of({ + type: "CREATE_NODE_COMMIT", + name: "/test/dir/file.txt", + } as ExplorerState.ICreateNodeCommitAction) + + const stateCopy = clone(ExplorerState.DefaultExplorerState) + const state = { + ...stateCopy, + register: { + ...stateCopy.register, + create: { + active: true, + nodeType: "file" as "file" | "folder", + name: "/test/dir/file.txt", + }, + }, + } + + const createState = mockStore(state) + + const expected = [{ type: "CREATE_NODE_FAIL", reason: "Duplicate" }] + + ExplorerState.createNodeEpic(action$, createState, { + fileSystem: { + ...fs, + writeFile: async folderpath => { + throw new Error("Duplicate") + }, + }, + notifications, + }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) + + it("Should trigger a persist/delete action if the created node is undone", () => { + const action$ = ActionsObservable.of({ + type: "UNDO", + } as ExplorerState.ExplorerAction) + + const stateCopy = clone(ExplorerState.DefaultExplorerState) + const state = { + ...stateCopy, + register: { + ...stateCopy.register, + undo: [ + { + type: "CREATE_NODE_SUCCESS", + name: "/test/dir/file.txt", + nodeType: "file", + } as ExplorerState.ICreateNodeSuccessAction, + ], + }, + } + + const undoState = mockStore(state) + const expected = [{ type: "UNDO_SUCCESS" }, { type: "REFRESH" }] + + ExplorerState.undoEpic(action$, undoState, { fileSystem: fs, notifications }) + .toArray() + .subscribe(actualActions => { + assert.deepEqual(actualActions, expected) + }) + }) }) describe("Store utility helper tests", () => { diff --git a/ui-tests/__snapshots__/NodeView.test.tsx.snap b/ui-tests/__snapshots__/NodeView.test.tsx.snap index d31ffa67f0..186a4e11f7 100644 --- a/ui-tests/__snapshots__/NodeView.test.tsx.snap +++ b/ui-tests/__snapshots__/NodeView.test.tsx.snap @@ -9,27 +9,29 @@ exports[`<NodeView /> Should match the snapshot 1`] = ` } } > - <DropTarget(DragSource(DragAndDrop)) - accepts={ - Array [ - "FILE", - "FOLDER", - ] - } - dragTarget="FILE" - isValidDrop={[Function]} - node={ - Object { - "filePath": "/test/a/file.txt", - "id": "2", - "indentationLevel": 2, - "modified": false, - "name": "file.txt", - "type": "file", + <div> + <DropTarget(DragSource(DragAndDrop)) + accepts={ + Array [ + "FILE", + "FOLDER", + ] } - } - onDrop={[Function]} - render={[Function]} - /> + dragTarget="FILE" + isValidDrop={[Function]} + node={ + Object { + "filePath": "/test/a/file.txt", + "id": "2", + "indentationLevel": 2, + "modified": false, + "name": "file.txt", + "type": "file", + } + } + onDrop={[Function]} + render={[Function]} + /> + </div> </styled.div> `; From 186a65cb6731748234f8c8cf3c0af727a36f0fe4 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Thu, 26 Apr 2018 11:54:10 -0700 Subject: [PATCH 55/59] Handle error event from chokidar, so that they don't bubble up as unhandled exceptions (#2142) --- browser/src/Services/FileSystemWatcher/index.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/browser/src/Services/FileSystemWatcher/index.ts b/browser/src/Services/FileSystemWatcher/index.ts index fdf2a5fcb2..b3210aadd4 100644 --- a/browser/src/Services/FileSystemWatcher/index.ts +++ b/browser/src/Services/FileSystemWatcher/index.ts @@ -2,6 +2,8 @@ import * as chokidar from "chokidar" import { Stats } from "fs" import { Event, IEvent } from "oni-types" +import * as Log from "./../../Log" + export type Targets = string | string[] interface IFSOptions { @@ -34,6 +36,10 @@ export class FileSystemWatcher { this._watcher.on("ready", () => { this._attachEventListeners() }) + + this._watcher.on("error", err => { + Log.warn("FileSystemWatcher encountered an error: " + err) + }) } public watch(target: Targets) { From 77889fae1c6aaf2ddf750041b995ca374f7b29ab Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Thu, 26 Apr 2018 15:39:44 -0700 Subject: [PATCH 56/59] Fix #2050 - Add a 'game loop' for the tutorials (#2128) * Add a 'game loop' to the tutorials * Remove the extra event listeners and pending tick state, since they are no longer needed * Remove tick code that is no longer needed from events * Add test case for TutorialGameplayManager * Fix lint issues --- .../Learning/Tutorial/TutorialBufferLayer.tsx | 11 +++ .../Tutorial/TutorialGameplayManager.ts | 32 +++----- .../Tutorial/TutorialGameplayManagerTests.ts | 73 +++++++++++++++++++ 3 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 browser/test/Services/Learning/Tutorial/TutorialGameplayManagerTests.ts diff --git a/browser/src/Services/Learning/Tutorial/TutorialBufferLayer.tsx b/browser/src/Services/Learning/Tutorial/TutorialBufferLayer.tsx index d9c42f42ce..dae057e180 100644 --- a/browser/src/Services/Learning/Tutorial/TutorialBufferLayer.tsx +++ b/browser/src/Services/Learning/Tutorial/TutorialBufferLayer.tsx @@ -221,6 +221,7 @@ export class TutorialBufferLayer implements Oni.BufferLayer { renderContext={context} onStateChangedEvent={this._onStateChangedEvent} innerRef={elem => (this._element = elem)} + onWillUnmount={() => this.stop()} /> ) } @@ -248,6 +249,10 @@ export class TutorialBufferLayer implements Oni.BufferLayer { windowManager.focusSplit("oni.window.0") } + public stop(): void { + this._tutorialGameplayManager.stop() + } + private _spawnParticles( color: string, position: Vector, @@ -277,6 +282,8 @@ export interface ITutorialBufferLayerViewProps { editor: NeovimEditor onStateChangedEvent: IEvent<IGameplayStateChangedEvent> innerRef: (elem: HTMLElement) => void + + onWillUnmount: () => void } export interface ITutorialBufferLayerState { @@ -399,6 +406,10 @@ export class TutorialBufferLayerView extends React.PureComponent< }) } + public componentWillUnmount(): void { + this.props.onWillUnmount() + } + public render(): JSX.Element { if (!this.state.tutorialState || !this.state.tutorialState.metadata) { return null diff --git a/browser/src/Services/Learning/Tutorial/TutorialGameplayManager.ts b/browser/src/Services/Learning/Tutorial/TutorialGameplayManager.ts index c9b9dfb3ce..47ea9d8525 100644 --- a/browser/src/Services/Learning/Tutorial/TutorialGameplayManager.ts +++ b/browser/src/Services/Learning/Tutorial/TutorialGameplayManager.ts @@ -5,7 +5,6 @@ import * as Oni from "oni-api" import { Event, IEvent } from "oni-types" - import { ITutorial, ITutorialMetadata, ITutorialStage } from "./ITutorial" export interface ITutorialState { @@ -21,6 +20,8 @@ export interface ITutorialState { * - Calls the 'render' function */ +export const TICK_RATE = 50 /* 50 ms, or 20 times pers second */ + export class TutorialGameplayManager { private _activeTutorial: ITutorial private _currentStageIdx: number @@ -30,8 +31,8 @@ export class TutorialGameplayManager { private _onTick = new Event<void>() private _isTickInProgress: boolean = false - private _isPendingTick: boolean = false private _buf: Oni.Buffer + private _pendingTimer: number | null = null public get onStateChanged(): IEvent<ITutorialState> { return this._onStateChanged @@ -64,23 +65,20 @@ export class TutorialGameplayManager { this._currentStageIdx = 0 this._activeTutorial = tutorial - this._editor.onModeChanged.subscribe((evt: string) => { - this._tick() - }) - - this._editor.onBufferChanged.subscribe(() => { - this._tick() - }) - ;(this._editor as any).onCursorMoved.subscribe(() => { - this._tick() - }) + this._pendingTimer = window.setInterval(() => this._tick(), TICK_RATE) this._tick() } + public stop(): void { + if (this._pendingTimer) { + window.clearInterval(this._pendingTimer) + this._pendingTimer = null + } + } + private async _tick(): Promise<void> { if (this._isTickInProgress) { - this._isPendingTick = true return } @@ -103,9 +101,6 @@ export class TutorialGameplayManager { if (this._currentStageIdx >= this._activeTutorial.stages.length) { this._onCompleted.dispatch(true) } - - // If we're on a new change, schedule a tick - window.setTimeout(() => this._tick()) } const goalsToSend = this._activeTutorial.stages.map(f => f.goalName) @@ -121,10 +116,5 @@ export class TutorialGameplayManager { } this._currentState = newState this._onStateChanged.dispatch(newState) - - if (this._isPendingTick) { - this._isPendingTick = false - await this._tick() - } } } diff --git a/browser/test/Services/Learning/Tutorial/TutorialGameplayManagerTests.ts b/browser/test/Services/Learning/Tutorial/TutorialGameplayManagerTests.ts new file mode 100644 index 0000000000..590f7d2533 --- /dev/null +++ b/browser/test/Services/Learning/Tutorial/TutorialGameplayManagerTests.ts @@ -0,0 +1,73 @@ +/** + * TutorialGameplayManagerTests.ts + */ + +import * as assert from "assert" + +import * as Oni from "oni-api" + +import { MockEditor } from "./../../../Mocks" +import * as TestHelpers from "./../../../TestHelpers" + +import { ITutorialMetadata } from "./../../../../src/Services/Learning/Tutorial" +import { + TICK_RATE, + TutorialGameplayManager, +} from "./../../../../src/Services/Learning/Tutorial/TutorialGameplayManager" + +const MockTutorialMetadata: ITutorialMetadata = { + id: "tutorial.test", + name: "test tutorial", + description: "tutorial for unit tests", + level: -1, +} + +// Helper to execute a 'tick', so that the 'setInterval' that runs the ticks +// gets picked up +const tick = async () => { + await TestHelpers.waitForPromiseResolution() + TestHelpers.tick(TICK_RATE + 1) +} + +describe("TutorialGameplayManagerTests", () => { + let mockEditor: Oni.Editor = null + let tutorialGameplayManager: TutorialGameplayManager = null + + beforeEach(() => { + mockEditor = new MockEditor() + tutorialGameplayManager = new TutorialGameplayManager(mockEditor) + }) + + it("calls tick periodically while active", async () => { + let hitCount = 0 + + const tickFunction = () => { + hitCount++ + return Promise.resolve(false) + } + + const myTutorial = { + metadata: MockTutorialMetadata, + stages: [ + { + tickFunction, + }, + ], + } + + tutorialGameplayManager.start(myTutorial, mockEditor.activeBuffer) + + // Validate the tick function was executed + assert.strictEqual(hitCount, 1) + + // Validate that another 'tick' was executed + await tick() + assert.strictEqual(hitCount, 2) + + tutorialGameplayManager.stop() + + // Validate that there wasn't another tick after stopping + await tick() + assert.strictEqual(hitCount, 2) + }) +}) From 6d2d7df9b2a159bb09dc58d2ae53ef0bc767aa3c Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Thu, 26 Apr 2018 15:56:09 -0700 Subject: [PATCH 57/59] Add Nathan Ensmenger as a backer - thank you! :) --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index eda194cdaf..7f73d5d029 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -85,6 +85,7 @@ Thanks you to all our backers for making Oni possible! * @mchalkley * @am2605 +* Nathan Ensmenger ## Backers via OpenCollective From be90b0483d495325d0be075046318a08ffbd8f27 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Thu, 26 Apr 2018 15:59:38 -0700 Subject: [PATCH 58/59] Add Leo Critchley as a backer - thank you! :) --- BACKERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BACKERS.md b/BACKERS.md index 7f73d5d029..867ca0507a 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -111,6 +111,7 @@ Thanks you to all our backers for making Oni possible! * Paul Baumgart * Kaiden Sin * Troy Vitullo +* Leo Critchley <a href="https://opencollective.com/oni/tiers/backer/0/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/0/avatar.png"></a> <a href="https://opencollective.com/oni/tiers/backer/1/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/1/avatar.png"></a> From ecb0a767c395883db0702ea918a0a5757d23c393 Mon Sep 17 00:00:00 2001 From: Bryan Phelps <bryphe@outlook.com> Date: Thu, 26 Apr 2018 16:01:43 -0700 Subject: [PATCH 59/59] Add Patrick Massot as a backer - thank you! :) --- .github/config.yml | 1 + BACKERS.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/config.yml b/.github/config.yml index 8975e058e3..289126c333 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -29,3 +29,4 @@ backers: - 6803419 - 1718128 - 2042893 +- 14060883 diff --git a/BACKERS.md b/BACKERS.md index 867ca0507a..3d1666022e 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -112,6 +112,7 @@ Thanks you to all our backers for making Oni possible! * Kaiden Sin * Troy Vitullo * Leo Critchley +* Patrick Massot <a href="https://opencollective.com/oni/tiers/backer/0/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/0/avatar.png"></a> <a href="https://opencollective.com/oni/tiers/backer/1/website" target="_blank"><img src="https://opencollective.com/oni/tiers/backer/1/avatar.png"></a>