mirror of https://github.com/onivim/oni.git
Merge branch 'master' into staging
This commit is contained in:
commit
03d7c26207
|
@ -38,3 +38,5 @@ backers:
|
|||
- 2318955
|
||||
- 28788713
|
||||
- 1491574
|
||||
- 6972449
|
||||
- 20133970
|
||||
|
|
|
@ -144,6 +144,9 @@ Thanks you to all our backers for making Oni possible!
|
|||
* Jonas Strømsodd
|
||||
* Trevor Barton
|
||||
* Tercio de Melo
|
||||
* Jon Plotner
|
||||
* Patrick Ball
|
||||
* Grégory Reinbold
|
||||
|
||||
<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>
|
||||
|
|
46
README.md
46
README.md
|
@ -1,12 +1,34 @@
|
|||
![alt text](./assets/oni-header.png)
|
||||
<p align="center">
|
||||
<img src="./assets/oni-header.png" alt="Logo">
|
||||
<h3 align="center">Modern Modal Editing</h3>
|
||||
</p>
|
||||
|
||||
### Modern Modal Editing
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/onivim/oni">
|
||||
<img src="https://travis-ci.org/onivim/oni.svg?branch=master" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://ci.appveyor.com/project/oni/oni">
|
||||
<img src="https://ci.appveyor.com/api/projects/status/s13bs7ail9ihkpnm?svg=true" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/onivim/oni">
|
||||
<img src="https://codecov.io/gh/onivim/oni/branch/master/graph/badge.svg" alt="codecov">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[![Build Status](https://travis-ci.org/onivim/oni.svg?branch=master)](https://travis-ci.org/onivim/oni) [![Build status](https://ci.appveyor.com/api/projects/status/s13bs7ail9ihkpnm?svg=true)](https://ci.appveyor.com/project/oni/oni) [![codecov](https://codecov.io/gh/onivim/oni/branch/master/graph/badge.svg)](https://codecov.io/gh/onivim/oni)
|
||||
|
||||
[![Join the chat on discord!](https://img.shields.io/discord/417774914645262338.svg)](https://discord.gg/7maEAxV)
|
||||
[![Backers on Open Collective](https://opencollective.com/oni/backers/badge.svg)](https://opencollective.com/oni#backer) [![BountySource Active Bounties](https://api.bountysource.com/badge/tracker?tracker_id=48462304)](https://www.bountysource.com/teams/oni)
|
||||
[![Total Downloads](https://img.shields.io/github/downloads/onivim/oni/total.svg)](https://github.com/onivim/oni/releases)
|
||||
<p align="center">
|
||||
<a href="https://discord.gg/7maEAxV">
|
||||
<img src="https://img.shields.io/discord/417774914645262338.svg" alt="Join the chat on discord!">
|
||||
</a>
|
||||
<a href="https://opencollective.com/oni#backer">
|
||||
<img src="https://opencollective.com/oni/backers/badge.svg" alt="Backers on Open Collective">
|
||||
</a>
|
||||
<a href="https://www.bountysource.com/teams/oni">
|
||||
<img src="https://api.bountysource.com/badge/tracker?tracker_id=48462304" alt="BountySource Active Bounties">
|
||||
</a>
|
||||
<a href="https://github.com/onivim/oni/releases">
|
||||
<img src="https://img.shields.io/github/downloads/onivim/oni/total.svg" alt="Total Downloads">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h2 align="center">Supporting Oni</h2>
|
||||
|
||||
|
@ -113,6 +135,16 @@ The goal of this project is to give an editor that gives the best of both worlds
|
|||
* [FAQ](https://github.com/onivim/oni/wiki/FAQ)
|
||||
* [Roadmap](https://github.com/onivim/oni/wiki/Roadmap)
|
||||
|
||||
## Available Plugins
|
||||
|
||||
Some available plugins created by Oni users are listed below (if you'd like to add your
|
||||
plugin to this list please create a PR updating this **README** with the details).
|
||||
|
||||
* [Oni Touchbar Plugin](https://github.com/jordan-arenstein/oni-plugin-touchbar) - by [jordan-arenstein](https://github.com/jordan-arenstein?tab=overview&from=2018-07-01&to=2018-07-31)
|
||||
* [quickFind](https://github.com/marene/quickFind) - by [marene](https://github.com/marene)
|
||||
* Themes
|
||||
* [Night Owl](https://github.com/Akin909/oni-theme-night-owl)
|
||||
|
||||
## Contributing
|
||||
|
||||
There many ways to get involved & contribute to Oni:
|
||||
|
|
57
appveyor.yml
57
appveyor.yml
|
@ -1,22 +1,22 @@
|
|||
# Test against the latest version of this Node.js version
|
||||
environment:
|
||||
nodejs_version: "8"
|
||||
nodejs_version: "8"
|
||||
|
||||
os: unstable
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^release.*/
|
||||
- master
|
||||
- /^release.*/
|
||||
|
||||
# Skip CI build if the changes match these rules exactly.
|
||||
# Ie, if the BACKERS.md file is changed, we don't need to build.
|
||||
skip_commits:
|
||||
files:
|
||||
- '**/*.md'
|
||||
files:
|
||||
- "**/*.md"
|
||||
|
||||
cache:
|
||||
- .oni_build_cache -> package.json
|
||||
- .oni_build_cache -> package.json
|
||||
|
||||
platform:
|
||||
- x86
|
||||
|
@ -24,42 +24,21 @@ platform:
|
|||
|
||||
# Install scripts. (runs after repo cloning)
|
||||
install:
|
||||
# Ensure the Git Submoduldes have been pulled down too
|
||||
- git submodule update --init --recursive
|
||||
# Get the latest stable version of Node.js or io.js
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
# Workaround https://github.com/npm/npm/issues/18380
|
||||
- npm install -g yarn
|
||||
- node --version
|
||||
- npm --version
|
||||
# install modules
|
||||
- yarn install
|
||||
- yarn run check-cached-binaries
|
||||
|
||||
artifacts:
|
||||
- path: dist/*.exe
|
||||
name: SetupExe
|
||||
|
||||
- path: dist/*.zip
|
||||
name: ProductZip
|
||||
|
||||
- path: dist/media/screenshot-win32.png
|
||||
name: DemoScreenshot
|
||||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
repository: onivim/oni
|
||||
auth_token:
|
||||
secure: IUThGC/uAhOIpZ+B/yS/tMBPBETwL1qttaaTbZYmbSP468Lmd0buoleDLSxrrLpH
|
||||
draft: false
|
||||
prerelease: false
|
||||
force_update: true
|
||||
on:
|
||||
appveyor_repo_tag: true
|
||||
# Ensure the Git Submoduldes have been pulled down too
|
||||
- git submodule update --init --recursive
|
||||
# Get the latest stable version of Node.js or io.js
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
# Workaround https://github.com/npm/npm/issues/18380
|
||||
- npm install -g yarn
|
||||
- node --version
|
||||
- npm --version
|
||||
# install modules
|
||||
- yarn install
|
||||
- yarn run check-cached-binaries
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
- powershell build/script/appveyor-test.ps1
|
||||
- powershell build/script/appveyor-test.ps1
|
||||
|
||||
# Don't actually build.
|
||||
build: off
|
||||
|
|
|
@ -105,7 +105,7 @@ export const start = async (args: string[]): Promise<void> => {
|
|||
const cssPromise = import("./CSS")
|
||||
const completionProvidersPromise = import("./Services/Completion/CompletionProviders")
|
||||
|
||||
const parsedArgs = minimist(args)
|
||||
const parsedArgs = minimist(args, { string: "_" })
|
||||
const currentWorkingDirectory = process.cwd()
|
||||
const normalizedFiles = parsedArgs._.map(
|
||||
arg => (path.isAbsolute(arg) ? arg : path.join(currentWorkingDirectory, arg)),
|
||||
|
|
|
@ -16,8 +16,13 @@ export interface IBufferHighlightsUpdater {
|
|||
clearHighlightsForLine(line: number): void
|
||||
}
|
||||
|
||||
// Helper class to efficiently update
|
||||
// buffer highlights in a batch.
|
||||
/**
|
||||
* Helper class to efficiently update
|
||||
* buffer highlights in a batch
|
||||
*
|
||||
* @name BufferHighlightsUpdater
|
||||
* @class
|
||||
*/
|
||||
export class BufferHighlightsUpdater implements IBufferHighlightsUpdater {
|
||||
private _calls: any[] = []
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ import * as types from "vscode-languageserver-types"
|
|||
|
||||
import { Event, IEvent } from "oni-types"
|
||||
|
||||
import { getDocumentationText } from "../../Plugins/Api/LanguageClient/LanguageClientHelpers"
|
||||
|
||||
import { ContextMenu } from "./../../Services/ContextMenu"
|
||||
|
||||
import * as CompletionUtility from "./../../Services/Completion/CompletionUtility"
|
||||
|
@ -64,7 +66,7 @@ const _convertCompletionForContextMenu = (completion: types.CompletionItem): any
|
|||
|
||||
const getCompletionDocumentation = (item: types.CompletionItem): string | null => {
|
||||
if (item.documentation) {
|
||||
return item.documentation
|
||||
return getDocumentationText(item.documentation)
|
||||
} else if (item.data && item.data.documentation) {
|
||||
return item.data.documentation
|
||||
} else {
|
||||
|
|
|
@ -315,19 +315,15 @@ export class NeovimEditor extends Editor implements Oni.Editor {
|
|||
this._actions.setColors(updatedColors)
|
||||
}
|
||||
|
||||
this._colors.onColorsChanged.subscribe(() => onColorsChanged())
|
||||
this._colors.onColorsChanged.subscribe(onColorsChanged)
|
||||
onColorsChanged()
|
||||
|
||||
const onTokenColorschanged = () => {
|
||||
if (this._neovimInstance.isInitialized) {
|
||||
this._neovimInstance.tokenColorSynchronizer.synchronizeTokenColors(
|
||||
this._tokenColors.tokenColors,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
this.trackDisposable(
|
||||
this._tokenColors.onTokenColorsChanged.subscribe(() => onTokenColorschanged()),
|
||||
this._tokenColors.onTokenColorsChanged.subscribe(() => {
|
||||
if (this._neovimInstance.isInitialized) {
|
||||
this._syntaxHighlighter.notifyColorschemeRedraw(`${this.activeBuffer.id}`)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
// Overlays
|
||||
|
@ -1292,6 +1288,8 @@ export class NeovimEditor extends Editor implements Oni.Editor {
|
|||
|
||||
private async _onColorsChanged(): Promise<void> {
|
||||
const newColorScheme = await this._neovimInstance.eval<string>("g:colors_name")
|
||||
const { bufferNumber } = await this._neovimInstance.getContext()
|
||||
this._syntaxHighlighter.notifyColorschemeRedraw(`${bufferNumber}`)
|
||||
|
||||
// In error cases, the neovim API layer returns an array
|
||||
if (typeof newColorScheme !== "string") {
|
||||
|
|
|
@ -2,18 +2,20 @@
|
|||
* CodeAction.ts
|
||||
*
|
||||
*/
|
||||
|
||||
import * as _ from "lodash"
|
||||
import { ErrorCodes } from "vscode-jsonrpc/lib/messages"
|
||||
import * as types from "vscode-languageserver-types"
|
||||
|
||||
import * as Oni from "oni-api"
|
||||
|
||||
import { MenuManager } from "./../../Services/Menu"
|
||||
import * as Log from "oni-core-logging"
|
||||
|
||||
import { LanguageManager } from "./../../Services/Language"
|
||||
import { Menu, MenuManager } from "./../../Services/Menu"
|
||||
|
||||
import * as Helpers from "./../../Plugins/Api/LanguageClient/LanguageClientHelpers"
|
||||
|
||||
import { asObservable } from "./../../Utility"
|
||||
import { asObservable, sleep } from "./../../Utility"
|
||||
|
||||
import { Definition } from "./Definition"
|
||||
|
||||
export class Symbols {
|
||||
|
@ -59,19 +61,9 @@ export class Symbols {
|
|||
.debounceTime(25)
|
||||
.do(() => menu.setLoading(true))
|
||||
.concatMap(async (newText: string) => {
|
||||
const buffer = this._editor.activeBuffer
|
||||
const symbols: types.SymbolInformation[] = await this._languageManager.sendLanguageServerRequest(
|
||||
buffer.language,
|
||||
buffer.filePath,
|
||||
"workspace/symbol",
|
||||
{
|
||||
textDocument: {
|
||||
uri: Helpers.wrapPathInFileUri(buffer.filePath),
|
||||
},
|
||||
query: newText,
|
||||
},
|
||||
)
|
||||
return symbols
|
||||
return this._requestSymbols(this._editor.activeBuffer, "workspace/symbol", menu, {
|
||||
query: newText,
|
||||
})
|
||||
})
|
||||
.subscribe((newItems: types.SymbolInformation[]) => {
|
||||
menu.setLoading(false)
|
||||
|
@ -94,15 +86,10 @@ export class Symbols {
|
|||
|
||||
const buffer = this._editor.activeBuffer
|
||||
|
||||
const result: types.SymbolInformation[] = await this._languageManager.sendLanguageServerRequest(
|
||||
buffer.language,
|
||||
buffer.filePath,
|
||||
const result: types.SymbolInformation[] = await this._requestSymbols(
|
||||
buffer,
|
||||
"textDocument/documentSymbol",
|
||||
{
|
||||
textDocument: {
|
||||
uri: Helpers.wrapPathInFileUri(buffer.filePath),
|
||||
},
|
||||
},
|
||||
menu,
|
||||
)
|
||||
|
||||
const options: Oni.Menu.MenuOption[] = result.map(item => this._symbolInfoToMenuItem(item))
|
||||
|
@ -175,4 +162,40 @@ export class Symbols {
|
|||
return "question"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request for symbols, retrying if the server is not ready, as long as the menu is open.
|
||||
*/
|
||||
private async _requestSymbols(
|
||||
buffer: Oni.Buffer,
|
||||
command: string,
|
||||
menu: Menu,
|
||||
options: any = {},
|
||||
): Promise<types.SymbolInformation[]> {
|
||||
while (menu.isOpen()) {
|
||||
try {
|
||||
return await this._languageManager.sendLanguageServerRequest(
|
||||
buffer.language,
|
||||
buffer.filePath,
|
||||
command,
|
||||
_.extend(
|
||||
{
|
||||
textDocument: {
|
||||
uri: Helpers.wrapPathInFileUri(buffer.filePath),
|
||||
},
|
||||
},
|
||||
options,
|
||||
),
|
||||
)
|
||||
} catch (e) {
|
||||
if (e.code === ErrorCodes.ServerNotInitialized) {
|
||||
Log.warn("[Symbols] Language server not yet initialised, trying again...")
|
||||
await sleep(1000)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,13 +42,13 @@ export const wrapPathInFileUri = (path: string) => getFilePrefix() + Utility.nor
|
|||
export const unwrapFileUriPath = (uri: string) => decodeURIComponent(uri.split(getFilePrefix())[1])
|
||||
|
||||
export const getTextFromContents = (
|
||||
contents: types.MarkedString | types.MarkedString[],
|
||||
contents: types.MarkedString | types.MarkupContent | types.MarkedString[],
|
||||
): IMarkedStringResult[] => {
|
||||
if (contents instanceof Array) {
|
||||
return contents.map(markedString => getTextFromMarkedString(markedString))
|
||||
} else {
|
||||
return [getTextFromMarkedString(contents)]
|
||||
}
|
||||
const text = isMarkupContent(contents) ? getDocumentationText(contents) : contents
|
||||
return [getTextFromMarkedString(text)]
|
||||
}
|
||||
|
||||
export const pathToTextDocumentIdentifierParms = (path: string) => ({
|
||||
|
@ -151,3 +151,15 @@ const getFilePrefix = () => {
|
|||
return "file://"
|
||||
}
|
||||
}
|
||||
|
||||
export function isMarkupContent(input: any): input is types.MarkupContent {
|
||||
return typeof input === "object" && input !== null && "value" in input && "kind" in input
|
||||
}
|
||||
|
||||
export const getDocumentationText = (documentation: string | types.MarkupContent) => {
|
||||
// Documentation can be a string or an object specifying the documentations type as well as the value.
|
||||
if (typeof documentation === "string") {
|
||||
return documentation
|
||||
}
|
||||
return documentation.value
|
||||
}
|
||||
|
|
|
@ -10,19 +10,38 @@ export interface IShellEnvironmentFetcher {
|
|||
getEnvironmentVariables(): Promise<any>
|
||||
}
|
||||
|
||||
interface IShellEnv {
|
||||
default: {
|
||||
sync: (shell?: string) => NodeJS.ProcessEnv
|
||||
}
|
||||
}
|
||||
|
||||
export class ShellEnvironmentFetcher implements IShellEnvironmentFetcher {
|
||||
private _shellEnvPromise: Promise<any>
|
||||
private _shellEnv: any
|
||||
private _shellEnv: IShellEnv
|
||||
|
||||
constructor() {
|
||||
// Dynamic imports return { default: Module }
|
||||
this._shellEnvPromise = import("shell-env")
|
||||
}
|
||||
|
||||
public async getEnvironmentVariables(): Promise<any> {
|
||||
public async getEnvironmentVariables(): Promise<NodeJS.ProcessEnv> {
|
||||
if (!this._shellEnv) {
|
||||
this._shellEnv = await this._shellEnvPromise
|
||||
return this._shellEnv.sync()
|
||||
}
|
||||
try {
|
||||
const userShell = configuration.getValue<string>("oni.userShell")
|
||||
const shell = typeof userShell === "string" ? userShell : undefined
|
||||
const env = this._shellEnv.default.sync(shell)
|
||||
return env
|
||||
} catch (error) {
|
||||
Log.warn(
|
||||
`[Oni environment fetcher]: unable to get enviroment variables because: ${
|
||||
error.message
|
||||
}`,
|
||||
)
|
||||
}
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,21 +148,35 @@ export class Process implements Oni.Process {
|
|||
|
||||
try {
|
||||
if (!this._env) {
|
||||
this._env = (await this._shellEnvironmentFetcher.getEnvironmentVariables()) || {}
|
||||
this._env = await this._shellEnvironmentFetcher.getEnvironmentVariables()
|
||||
}
|
||||
existingPath = process.env.Path || process.env.PATH
|
||||
} catch (e) {
|
||||
existingPath = process.env.Path || process.env.PATH
|
||||
}
|
||||
|
||||
const additionalEnvironmentVariables =
|
||||
configuration.getValue("environment.additionalVariables") || {}
|
||||
|
||||
const requiredOptions = {
|
||||
env: {
|
||||
...process.env,
|
||||
...this._env,
|
||||
...originalSpawnOptions.env,
|
||||
...additionalEnvironmentVariables,
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: Workaround for the bug fix here:
|
||||
// https://github.com/neovim/neovim/pull/9345
|
||||
// Once 0.3.2 is available and we've switched, we won't need this anymore.
|
||||
if (Platform.isMac() && !requiredOptions.env.LANG) {
|
||||
requiredOptions.env.LANG = "en_us.UTF-8"
|
||||
Log.warn(
|
||||
"'LANG' environment variable not set, using default value of 'en_us.UTF-8'. Consider setting environment.additionalVariables['LANG'].",
|
||||
)
|
||||
}
|
||||
|
||||
requiredOptions.env.PATH = this.mergePathEnvironmentVariable(
|
||||
existingPath,
|
||||
configuration.getValue("environment.additionalPaths"),
|
||||
|
|
|
@ -146,7 +146,7 @@ export class CanvasRenderer implements INeovimRenderer {
|
|||
row.forEach((span: ISpan) => {
|
||||
// All spans that have changed in current rendering pass
|
||||
|
||||
const rowIndex = Number.parseInt(y)
|
||||
const rowIndex = Number.parseInt(y, 10)
|
||||
|
||||
const currentCell = screenInfo.getCell(span.startX, rowIndex)
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
*
|
||||
* Selectors are functions that take a state and derive a value from it.
|
||||
*/
|
||||
import * as isEqual from "lodash/isEqual"
|
||||
import * as omit from "lodash/omit"
|
||||
|
||||
import { ICompletionState } from "./CompletionState"
|
||||
|
||||
|
@ -67,25 +69,69 @@ export const filterCompletionOptions = (
|
|||
if (!searchText) {
|
||||
return items
|
||||
}
|
||||
|
||||
if (!items || !items.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Must start with first letter in searchText, and then be at least abbreviated by searchText.
|
||||
const filterRegEx = new RegExp("^" + searchText.split("").join(".*") + ".*")
|
||||
|
||||
const filteredOptions = items.filter(f => {
|
||||
const textToFilterOn = f.filterText || f.label
|
||||
return textToFilterOn.match(filterRegEx)
|
||||
})
|
||||
const sortedOptions = filteredOptions.sort((itemA, itemB) => {
|
||||
const itemASortText = itemA.filterText || itemA.label
|
||||
const itemBSortText = itemB.filterText || itemB.label
|
||||
|
||||
return filteredOptions.sort((itemA, itemB) => {
|
||||
const itemAFilterText = itemA.filterText || itemA.label
|
||||
const itemBFilterText = itemB.filterText || itemB.label
|
||||
const indexOfA = itemASortText.indexOf(searchText)
|
||||
const indexOfB = itemBSortText.indexOf(searchText)
|
||||
|
||||
const indexOfA = itemAFilterText.indexOf(searchText)
|
||||
const indexOfB = itemBFilterText.indexOf(searchText)
|
||||
|
||||
return indexOfB - indexOfA
|
||||
// Ensure abbreviated matches are sorted below exact matches.
|
||||
if (indexOfA >= 0 && indexOfB === -1) {
|
||||
return -1
|
||||
} else if (indexOfA === -1 && indexOfB >= 0) {
|
||||
return 1
|
||||
// Else sort by label to keep related results together.
|
||||
} else if (itemASortText < itemBSortText) {
|
||||
return -1
|
||||
} else if (itemASortText > itemBSortText) {
|
||||
return 1
|
||||
// Fallback to sort by language server specified sortText.
|
||||
} else if (itemA.sortText < itemB.sortText) {
|
||||
return -1
|
||||
} else if (itemA.sortText > itemB.sortText) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
// Language servers can return duplicate entries (e.g. cquery).
|
||||
const uniqueOptions: types.CompletionItem[] = _uniq(sortedOptions)
|
||||
|
||||
return uniqueOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unique completion items, assuming they're sorted so duplicates are contiguous.
|
||||
*
|
||||
* Adapted from https://github.com/lodash/lodash/blob/master/.internal/baseSortedUniq.js, since
|
||||
* lodash has no `sortedUniqWith` function.
|
||||
*/
|
||||
const _uniq = (array: types.CompletionItem[]) => {
|
||||
let seenReduced: any
|
||||
let index = -1
|
||||
let resIndex = 0
|
||||
|
||||
const { length } = array
|
||||
const result = []
|
||||
|
||||
while (++index < length) {
|
||||
const value = array[index]
|
||||
// Omit the `sortText` which can be different even if all other attributes are the same.
|
||||
const reduced = omit(value, "sortText")
|
||||
if (!index || !isEqual(reduced, seenReduced)) {
|
||||
seenReduced = reduced
|
||||
result[resIndex++] = value
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -134,6 +134,16 @@ export const completionResultsReducer: Reducer<ICompletionResults> = (
|
|||
return {
|
||||
...state,
|
||||
completions: state.completions.map(completion => {
|
||||
// Prefer `detail` field if available, to avoid splatting e.g. methods with
|
||||
// the same name but different signature.
|
||||
if (completion.detail && action.completionItemWithDetails.detail) {
|
||||
if (completion.detail === action.completionItemWithDetails.detail) {
|
||||
return action.completionItemWithDetails
|
||||
} else {
|
||||
return completion
|
||||
}
|
||||
}
|
||||
|
||||
if (completion.label === action.completionItemWithDetails.label) {
|
||||
return action.completionItemWithDetails
|
||||
} else {
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as Log from "oni-core-logging"
|
|||
import * as Helpers from "./../../Plugins/Api/LanguageClient/LanguageClientHelpers"
|
||||
|
||||
import { LanguageManager } from "./../Language"
|
||||
import { IServerCapabilities } from "./../Language/ServerCapabilities"
|
||||
|
||||
export interface CompletionsRequestContext {
|
||||
language: string
|
||||
|
@ -86,6 +87,12 @@ export class LanguageServiceCompletionsRequestor implements ICompletionsRequesto
|
|||
filePath: string,
|
||||
completionItem: types.CompletionItem,
|
||||
): Promise<types.CompletionItem> {
|
||||
const caps: IServerCapabilities = await this._languageManager.getCapabilitiesForLanguage(
|
||||
language,
|
||||
)
|
||||
if (!caps.completionProvider.resolveProvider) {
|
||||
return completionItem
|
||||
}
|
||||
let result
|
||||
try {
|
||||
result = await this._languageManager.sendLanguageServerRequest(
|
||||
|
|
|
@ -109,6 +109,8 @@ const BaseConfiguration: IConfigurationValues = {
|
|||
|
||||
"oni.enhancedSyntaxHighlighting": true,
|
||||
|
||||
"oni.userShell": undefined,
|
||||
|
||||
"oni.loadInitVim": false,
|
||||
|
||||
"oni.hideMenu": false,
|
||||
|
@ -147,6 +149,8 @@ const BaseConfiguration: IConfigurationValues = {
|
|||
"editor.quickOpen.alternativeOpenMode": Oni.FileOpenMode.ExistingTab,
|
||||
"editor.quickOpen.showHidden": true,
|
||||
|
||||
"quickOpen.defaultOpenMode": Oni.FileOpenMode.Edit,
|
||||
|
||||
"editor.split.mode": "native",
|
||||
|
||||
"editor.typingPrediction": true,
|
||||
|
@ -172,6 +176,7 @@ const BaseConfiguration: IConfigurationValues = {
|
|||
"explorer.maxUndoFileSizeInBytes": 500_000,
|
||||
|
||||
"environment.additionalPaths": [],
|
||||
"environment.additionalVariables": {},
|
||||
|
||||
"keyDisplayer.showInInsertMode": false,
|
||||
|
||||
|
@ -181,6 +186,14 @@ const BaseConfiguration: IConfigurationValues = {
|
|||
"language.go.languageServer.command": "go-langserver",
|
||||
"language.go.textMateGrammar": path.join(__dirname, "extensions", "go", "syntaxes", "go.json"),
|
||||
|
||||
"language.vue.textMateGrammar": path.join(
|
||||
__dirname,
|
||||
"extensions",
|
||||
"vue",
|
||||
"syntaxes",
|
||||
"vue.json",
|
||||
),
|
||||
|
||||
"language.python.languageServer.command": "pyls",
|
||||
"language.cpp.languageServer.command": "clangd",
|
||||
"language.c.languageServer.command": "clangd",
|
||||
|
|
|
@ -111,6 +111,10 @@ export interface IConfigurationValues {
|
|||
// Set this to 'false' to avoid loading the default config, and load settings from init.vim instead.
|
||||
"oni.useDefaultConfig": boolean
|
||||
|
||||
// This string represents the path to the shell that the user would like oni to use to extract
|
||||
// environment variables that it uses derives the $PATH variable from.
|
||||
"oni.userShell": string
|
||||
|
||||
// By default, user's init.vim is not loaded, to avoid conflicts.
|
||||
// Set this to `true` to enable loading of init.vim.
|
||||
// Set this to a string to override the init.vim path.
|
||||
|
@ -165,6 +169,9 @@ export interface IConfigurationValues {
|
|||
"editor.quickOpen.alternativeOpenMode": Oni.FileOpenMode
|
||||
"editor.quickOpen.showHidden": boolean
|
||||
|
||||
// this is new command to replace the above legacy editor prefixed command
|
||||
"quickOpen.defaultOpenMode": Oni.FileOpenMode
|
||||
|
||||
"editor.errors.slideOnFocus": boolean
|
||||
"editor.formatting.formatOnSwitchToNormalMode": boolean // TODO: Make this setting reliable. If formatting is slow, it will hose edits... not fun
|
||||
|
||||
|
@ -207,6 +214,9 @@ export interface IConfigurationValues {
|
|||
// (and available in terminal integration, later)
|
||||
"environment.additionalPaths": string[]
|
||||
|
||||
// Additional environment variables that override the default settings
|
||||
"environment.additionalVariables": any
|
||||
|
||||
// User configurable array of files for which
|
||||
// the image layer opens
|
||||
"editor.imageLayerExtensions": string[]
|
||||
|
|
|
@ -160,10 +160,6 @@ export class ContextMenu {
|
|||
)
|
||||
}
|
||||
|
||||
public updateItem(item: any): void {
|
||||
this._actions.setDetailedMenuItem(item)
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
this._actions.hidePopupMenu()
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import { ContextMenuState } from "./ContextMenu"
|
|||
export interface IContextMenuItem {
|
||||
label: string
|
||||
detail?: string
|
||||
documentation?: string
|
||||
documentation?: string | types.MarkupContent
|
||||
icon?: string
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ export interface KeyBindingMap {
|
|||
}
|
||||
|
||||
const MAX_DELAY_BETWEEN_KEY_CHORD = 250 /* milliseconds */
|
||||
const MAX_CHORD_SIZE = 4
|
||||
const MAX_CHORD_SIZE = 6
|
||||
|
||||
import { KeyboardResolver } from "./../Input/Keyboard/KeyboardResolver"
|
||||
|
||||
|
|
|
@ -16,14 +16,17 @@ export const sortTextEdits = (edits: types.TextEdit[]): types.TextEdit[] => {
|
|||
return sortedEdits
|
||||
}
|
||||
|
||||
export const convertTextDocumentEditsToFileMap = (
|
||||
edits: types.TextDocumentEdit[],
|
||||
export const convertTextDocumentChangesToFileMap = (
|
||||
edits: Array<types.TextDocumentEdit | types.CreateFile | types.RenameFile | types.DeleteFile>,
|
||||
): { [fileUri: string]: types.TextEdit[] } => {
|
||||
if (!edits) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return edits.reduce((prev, curr) => {
|
||||
if (!("textDocument" in curr)) {
|
||||
return prev
|
||||
}
|
||||
return {
|
||||
...prev,
|
||||
[curr.textDocument.uri]: edits,
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as React from "react"
|
|||
|
||||
import * as types from "vscode-languageserver-types"
|
||||
|
||||
import { getDocumentationText } from "../../Plugins/Api/LanguageClient/LanguageClientHelpers"
|
||||
import {
|
||||
QuickInfoDocumentation,
|
||||
QuickInfoElement,
|
||||
|
@ -66,7 +67,9 @@ export const getElementsFromType = (signatureHelp: types.SignatureHelp): JSX.Ele
|
|||
{elements}
|
||||
</Title>
|
||||
{!!(selectedArgument && selectedArgument.documentation) && (
|
||||
<QuickInfoDocumentation text={selectedArgument.documentation} />
|
||||
<QuickInfoDocumentation
|
||||
text={getDocumentationText(selectedArgument.documentation)}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)
|
||||
|
|
|
@ -66,13 +66,6 @@ export const setMenuItems = (id: string, items: any[]) => ({
|
|||
},
|
||||
})
|
||||
|
||||
export const setDetailedMenuItem = (item: any) => ({
|
||||
type: "SET_DETAILED_MENU_ITEM",
|
||||
payload: {
|
||||
detailedItem: item,
|
||||
},
|
||||
})
|
||||
|
||||
export const hidePopupMenu = () => (dispatch: any, getState: any) => {
|
||||
const state = getState()
|
||||
|
||||
|
|
|
@ -33,13 +33,6 @@ export interface IShowMenuAction {
|
|||
}
|
||||
}
|
||||
|
||||
export interface ISetDetailedMenuItem<T> {
|
||||
type: "SET_DETAILED_MENU_ITEM"
|
||||
payload: {
|
||||
detailedItem: T
|
||||
}
|
||||
}
|
||||
|
||||
export interface ISetMenuItems<T> {
|
||||
type: "SET_MENU_ITEMS"
|
||||
payload: {
|
||||
|
|
|
@ -63,32 +63,6 @@ export function createReducer<T, FilteredT extends T>() {
|
|||
isLoading: false,
|
||||
}
|
||||
}
|
||||
case "SET_DETAILED_MENU_ITEM": {
|
||||
if (!s || !s.options) {
|
||||
return s
|
||||
}
|
||||
|
||||
if (!a.payload.detailedItem) {
|
||||
return s
|
||||
}
|
||||
|
||||
const options = s.options.map(entry => {
|
||||
// TODO: Decide on canonical interface for menu options
|
||||
if ((entry as any).label === a.payload.detailedItem.label) {
|
||||
return a.payload.detailedItem
|
||||
} else {
|
||||
return entry
|
||||
}
|
||||
})
|
||||
|
||||
const filterFunc = s.filterFunction
|
||||
const filteredOptions2 = filterFunc(options, s.filter)
|
||||
return {
|
||||
...s,
|
||||
options,
|
||||
filteredOptions: filteredOptions2,
|
||||
}
|
||||
}
|
||||
case "SET_MENU_ITEMS": {
|
||||
if (!s || s.id !== a.payload.id) {
|
||||
return s
|
||||
|
@ -129,6 +103,8 @@ export function createReducer<T, FilteredT extends T>() {
|
|||
return s
|
||||
}
|
||||
|
||||
// Note that for language server completions, the `filterFunc` is a no-op - the
|
||||
// items are filtered elsewhere (but this FILTER_MENU action is still dispatched).
|
||||
const filterFunc = s.filterFunction
|
||||
const filteredOptionsSorted = filterFunc(s.options, a.payload.filter)
|
||||
|
||||
|
@ -136,6 +112,7 @@ export function createReducer<T, FilteredT extends T>() {
|
|||
...s,
|
||||
filter: a.payload.filter,
|
||||
filteredOptions: filteredOptionsSorted,
|
||||
selectedIndex: 0,
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -144,8 +144,8 @@ class Recorder implements Oni.Recorder {
|
|||
const toArrayBuffer = async (blob: Blob): Promise<ArrayBuffer> => {
|
||||
return new Promise<ArrayBuffer>((resolve, reject) => {
|
||||
const fileReader = new FileReader()
|
||||
fileReader.onload = function() {
|
||||
const arrayBuffer = this.result
|
||||
fileReader.onload = evt => {
|
||||
const arrayBuffer = fileReader.result as ArrayBuffer
|
||||
resolve(arrayBuffer)
|
||||
}
|
||||
fileReader.readAsArrayBuffer(blob)
|
||||
|
|
|
@ -12,6 +12,7 @@ import { ISyntaxHighlightTokenInfo } from "./SyntaxHighlightingStore"
|
|||
export interface ISyntaxHighlighter extends IDisposable {
|
||||
notifyBufferUpdate(evt: Oni.EditorBufferChangedEventArgs): Promise<void>
|
||||
notifyViewportChanged(bufferId: string, topLineInView: number, bottomLineInView: number): void
|
||||
notifyColorschemeRedraw(id: string): void
|
||||
|
||||
getHighlightTokenAt(bufferId: string, position: types.Position): ISyntaxHighlightTokenInfo
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
* Handles enhanced syntax highlighting
|
||||
*/
|
||||
|
||||
import { Buffer, Editor } from "oni-api"
|
||||
import * as Log from "oni-core-logging"
|
||||
|
||||
import { prettyPrint } from "./../../Utility"
|
||||
import { TokenColor, TokenColors } from "./../TokenColors"
|
||||
|
||||
import { NeovimEditor } from "./../../Editor/NeovimEditor"
|
||||
|
||||
import { HighlightInfo } from "./Definitions"
|
||||
import {
|
||||
ISyntaxHighlightLineInfo,
|
||||
|
@ -18,21 +18,37 @@ import {
|
|||
} from "./SyntaxHighlightingStore"
|
||||
import { TokenScorer } from "./TokenScorer"
|
||||
|
||||
import { IBufferHighlightsUpdater } from "../../Editor/BufferHighlights"
|
||||
import * as Selectors from "./SyntaxHighlightSelectors"
|
||||
|
||||
// SyntaxHighlightReconciler
|
||||
//
|
||||
// Essentially a renderer / reconciler, that will push
|
||||
// highlight calls to the active buffer based on the active
|
||||
// window and viewport
|
||||
interface IBufferWithSyntaxHighlighter extends Buffer {
|
||||
updateHighlights?: (
|
||||
tokenColors: TokenColor[],
|
||||
highlightCallback: (args: IBufferHighlightsUpdater) => void,
|
||||
) => void
|
||||
}
|
||||
|
||||
export interface IEditorWithSyntaxHighlighter extends Editor {
|
||||
activeBuffer: IBufferWithSyntaxHighlighter
|
||||
}
|
||||
|
||||
/**
|
||||
* SyntaxHighlightReconciler
|
||||
*
|
||||
* Essentially a renderer / reconciler, that will push
|
||||
* highlight calls to the active buffer based on the active
|
||||
* window and viewport
|
||||
* @name SyntaxHighlightReconciler
|
||||
* @class
|
||||
*/
|
||||
export class SyntaxHighlightReconciler {
|
||||
private _previousState: { [line: number]: ISyntaxHighlightLineInfo } = {}
|
||||
private _tokenScorer = new TokenScorer()
|
||||
|
||||
constructor(private _editor: NeovimEditor, private _tokenColors: TokenColors) {}
|
||||
constructor(private _editor: IEditorWithSyntaxHighlighter, private _tokenColors: TokenColors) {}
|
||||
|
||||
public update(state: ISyntaxHighlightState) {
|
||||
const activeBuffer: any = this._editor.activeBuffer
|
||||
const { activeBuffer } = this._editor
|
||||
|
||||
if (!activeBuffer) {
|
||||
return
|
||||
|
@ -77,6 +93,15 @@ export class SyntaxHighlightReconciler {
|
|||
}
|
||||
})
|
||||
|
||||
// Get only the token colors that apply to the visible section of the buffer
|
||||
const visibleTokens = tokens.reduce((accumulator, { highlights }) => {
|
||||
if (highlights) {
|
||||
const tokenColors = highlights.map(({ tokenColor }) => tokenColor)
|
||||
accumulator.push(...tokenColors)
|
||||
}
|
||||
return accumulator
|
||||
}, [])
|
||||
|
||||
filteredLines.forEach(line => {
|
||||
const lineNumber = parseInt(line, 10)
|
||||
this._previousState[line] = Selectors.getLineFromBuffer(
|
||||
|
@ -87,26 +112,22 @@ export class SyntaxHighlightReconciler {
|
|||
|
||||
if (tokens.length) {
|
||||
Log.verbose(
|
||||
"[SyntaxHighlightReconciler] Applying changes to " + tokens.length + " lines.",
|
||||
`[SyntaxHighlightReconciler] Applying changes to ${tokens.length} lines.`,
|
||||
)
|
||||
activeBuffer.updateHighlights(
|
||||
this._tokenColors.tokenColors,
|
||||
(highlightUpdater: any) => {
|
||||
tokens.forEach(token => {
|
||||
const { line, highlights } = token
|
||||
if (Log.isDebugLoggingEnabled()) {
|
||||
Log.debug(
|
||||
"[SyntaxHighlightingReconciler] Updating tokens for line: " +
|
||||
token.line +
|
||||
" | " +
|
||||
JSON.stringify(highlights),
|
||||
)
|
||||
}
|
||||
activeBuffer.updateHighlights(visibleTokens, highlightUpdater => {
|
||||
tokens.forEach(token => {
|
||||
const { line, highlights } = token
|
||||
if (Log.isDebugLoggingEnabled()) {
|
||||
Log.debug(
|
||||
`[SyntaxHighlightingReconciler] Updating tokens for line: ${line} | ${prettyPrint(
|
||||
highlights,
|
||||
)}`,
|
||||
)
|
||||
}
|
||||
|
||||
highlightUpdater.setHighlightsForLine(line, highlights)
|
||||
})
|
||||
},
|
||||
)
|
||||
highlightUpdater.setHighlightsForLine(line, highlights)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,8 +142,10 @@ export class SyntaxHighlightReconciler {
|
|||
}
|
||||
|
||||
private _getHighlightGroupFromScope(scopes: string[]): TokenColor {
|
||||
const configurationColors = this._tokenColors.tokenColors
|
||||
const highestRanked = this._tokenScorer.rankTokenScopes(scopes, configurationColors)
|
||||
const highestRanked = this._tokenScorer.rankTokenScopes(
|
||||
scopes,
|
||||
this._tokenColors.tokenColors,
|
||||
)
|
||||
return highestRanked
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,10 @@ import {
|
|||
} from "./SyntaxHighlightingStore"
|
||||
|
||||
import { ISyntaxHighlighter } from "./ISyntaxHighlighter"
|
||||
import { SyntaxHighlightReconciler } from "./SyntaxHighlightReconciler"
|
||||
import {
|
||||
IEditorWithSyntaxHighlighter,
|
||||
SyntaxHighlightReconciler,
|
||||
} from "./SyntaxHighlightReconciler"
|
||||
import { getLineFromBuffer } from "./SyntaxHighlightSelectors"
|
||||
|
||||
import * as Utility from "./../../Utility"
|
||||
|
@ -45,7 +48,10 @@ export class SyntaxHighlighter implements ISyntaxHighlighter {
|
|||
constructor(private _editor: NeovimEditor, private _tokenColors: TokenColors) {
|
||||
this._store = createSyntaxHighlightStore()
|
||||
|
||||
this._reconciler = new SyntaxHighlightReconciler(this._editor, this._tokenColors)
|
||||
this._reconciler = new SyntaxHighlightReconciler(
|
||||
this._editor as IEditorWithSyntaxHighlighter,
|
||||
this._tokenColors,
|
||||
)
|
||||
this._unsubscribe = this._store.subscribe(() => {
|
||||
const state = this._store.getState()
|
||||
this._reconciler.update(state)
|
||||
|
@ -62,12 +68,10 @@ export class SyntaxHighlighter implements ISyntaxHighlighter {
|
|||
bottomLineInView: number,
|
||||
): void {
|
||||
Log.verbose(
|
||||
"[SyntaxHighlighting.notifyViewportChanged] - bufferId: " +
|
||||
bufferId +
|
||||
" topLineInView: " +
|
||||
topLineInView +
|
||||
" bottomLineInView: " +
|
||||
bottomLineInView,
|
||||
`[SyntaxHighlighting.notifyViewportChanged] -
|
||||
bufferId: ${bufferId}
|
||||
topLineInView: ${topLineInView}
|
||||
bottomLineInView: ${bottomLineInView}`,
|
||||
)
|
||||
|
||||
const state = this._store.getState()
|
||||
|
@ -89,6 +93,10 @@ export class SyntaxHighlighter implements ISyntaxHighlighter {
|
|||
})
|
||||
}
|
||||
|
||||
public async notifyColorschemeRedraw(bufferId: string) {
|
||||
this._store.dispatch({ type: "SYNTAX_RESET_BUFFER", bufferId })
|
||||
}
|
||||
|
||||
public async notifyBufferUpdate(evt: Oni.EditorBufferChangedEventArgs): Promise<void> {
|
||||
const firstChange = evt.contentChanges[0]
|
||||
if (!firstChange.range && !firstChange.rangeLength) {
|
||||
|
@ -157,6 +165,10 @@ export class NullSyntaxHighlighter implements ISyntaxHighlighter {
|
|||
return null
|
||||
}
|
||||
|
||||
public notifyColorschemeRedraw(id: string): void {
|
||||
return null
|
||||
}
|
||||
|
||||
public notifyViewportChanged(
|
||||
bufferId: string,
|
||||
topLineInView: number,
|
||||
|
|
|
@ -51,6 +51,11 @@ export const bufferReducer: Reducer<IBufferSyntaxHighlightState> = (
|
|||
action: ISyntaxHighlightAction,
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case "SYNTAX_RESET_BUFFER":
|
||||
return {
|
||||
...state,
|
||||
lines: linesReducer(state.lines, action),
|
||||
}
|
||||
case "SYNTAX_UPDATE_BUFFER":
|
||||
return {
|
||||
...state,
|
||||
|
@ -125,6 +130,21 @@ export const linesReducer: Reducer<SyntaxHighlightLines> = (
|
|||
}
|
||||
return newState
|
||||
}
|
||||
case "SYNTAX_RESET_BUFFER":
|
||||
const resetState = Object.entries(state).reduce<SyntaxHighlightLines>(
|
||||
(newResetState, [lineNumber, line]) => {
|
||||
newResetState[lineNumber] = {
|
||||
tokens: [],
|
||||
ruleStack: null,
|
||||
...line,
|
||||
dirty: true,
|
||||
}
|
||||
return newResetState
|
||||
},
|
||||
{},
|
||||
)
|
||||
return resetState
|
||||
|
||||
case "SYNTAX_UPDATE_BUFFER":
|
||||
const updatedBufferState: SyntaxHighlightLines = {
|
||||
...state,
|
||||
|
|
|
@ -73,6 +73,10 @@ export const DefaultSyntaxHighlightState: ISyntaxHighlightState = {
|
|||
}
|
||||
|
||||
export type ISyntaxHighlightAction =
|
||||
| {
|
||||
type: "SYNTAX_RESET_BUFFER"
|
||||
bufferId: string
|
||||
}
|
||||
| {
|
||||
type: "SYNTAX_UPDATE_BUFFER"
|
||||
language: string
|
||||
|
@ -150,14 +154,14 @@ const updateBufferLineMiddleware = (store: any) => (next: any) => (action: any)
|
|||
action.lineNumber === 0 ? null : buffer.lines[action.lineNumber - 1].ruleStack
|
||||
const tokenizeResult = grammar.tokenizeLine(action.line, previousRuleStack)
|
||||
|
||||
const tokens = tokenizeResult.tokens.map((t: any) => ({
|
||||
const tokens = tokenizeResult.tokens.map(token => ({
|
||||
range: types.Range.create(
|
||||
action.lineNumber,
|
||||
t.startIndex,
|
||||
token.startIndex,
|
||||
action.lineNumber,
|
||||
t.endIndex,
|
||||
token.endIndex,
|
||||
),
|
||||
scopes: t.scopes,
|
||||
scopes: token.scopes,
|
||||
}))
|
||||
|
||||
const updateInsertLineAction: ISyntaxHighlightAction = {
|
||||
|
@ -180,7 +184,11 @@ const updateBufferLineMiddleware = (store: any) => (next: any) => (action: any)
|
|||
const updateTokenMiddleware = (store: any) => (next: any) => (action: any) => {
|
||||
const result: ISyntaxHighlightAction = next(action)
|
||||
|
||||
if (action.type === "SYNTAX_UPDATE_BUFFER" || action.type === "SYNTAX_UPDATE_BUFFER_VIEWPORT") {
|
||||
if (
|
||||
action.type === "SYNTAX_UPDATE_BUFFER" ||
|
||||
action.type === "SYNTAX_UPDATE_BUFFER_VIEWPORT" ||
|
||||
action.type === "SYNTAX_RESET_BUFFER"
|
||||
) {
|
||||
const state: ISyntaxHighlightState = store.getState()
|
||||
const bufferId = action.bufferId
|
||||
|
||||
|
@ -212,7 +220,7 @@ const updateTokenMiddleware = (store: any) => (next: any) => (action: any) => {
|
|||
|
||||
syntaxHighlightingJobs.startJob(
|
||||
new SyntaxHighlightingPeriodicJob(
|
||||
store as any,
|
||||
store,
|
||||
action.bufferId,
|
||||
grammar,
|
||||
relevantRange.top,
|
||||
|
|
|
@ -119,7 +119,7 @@ export class TokenScorer {
|
|||
if (parts.length < 2) {
|
||||
return null
|
||||
}
|
||||
const matchingToken = theme.find(color => color.scope === scope)
|
||||
const matchingToken = theme.find(color => color.scope.includes(scope))
|
||||
if (matchingToken) {
|
||||
return matchingToken
|
||||
}
|
||||
|
|
|
@ -190,8 +190,8 @@ class TokenThemeProvider extends React.Component<IProps, IState> {
|
|||
|
||||
public generateTokens({ defaultMap = defaultsToMap, defaultTokens }: IGenerateTokenArgs) {
|
||||
const newTokens = Object.keys(defaultMap).reduce((acc, defaultTokenName) => {
|
||||
const defaultToken = this.props.tokenColors.find(
|
||||
token => token.scope === defaultTokenName,
|
||||
const defaultToken = this.props.tokenColors.find(token =>
|
||||
token.scope.includes(defaultTokenName),
|
||||
)
|
||||
if (defaultToken) {
|
||||
const tokens = defaultMap[defaultTokenName].map(name =>
|
||||
|
|
|
@ -35,6 +35,7 @@ export interface IThemeColors {
|
|||
|
||||
"tabs.background": string
|
||||
"tabs.foreground": string
|
||||
"tabs.borderBottom": string
|
||||
"tabs.active.foreground": string
|
||||
"tabs.active.background": string
|
||||
|
||||
|
@ -288,6 +289,7 @@ export const DefaultThemeColors: IThemeColors = {
|
|||
|
||||
"tabs.background": ColorBlack,
|
||||
"tabs.foreground": ColorWhite,
|
||||
"tabs.borderBottom": null,
|
||||
"tabs.active.background": null,
|
||||
"tabs.active.foreground": null,
|
||||
|
||||
|
|
|
@ -8,8 +8,11 @@
|
|||
|
||||
import { Event, IDisposable, IEvent } from "oni-types"
|
||||
|
||||
import { Configuration, IConfigurationValues } from "./Configuration"
|
||||
import { ThemeManager } from "./Themes"
|
||||
|
||||
export interface TokenColor {
|
||||
scope: string
|
||||
scope: string[]
|
||||
settings: TokenColorStyle
|
||||
// private field for determining where a token came from
|
||||
_source?: string
|
||||
|
@ -18,6 +21,7 @@ export interface TokenColor {
|
|||
export interface ThemeToken {
|
||||
scope: string | string[]
|
||||
settings: TokenColorStyle
|
||||
_source?: string
|
||||
}
|
||||
|
||||
export interface TokenColorStyle {
|
||||
|
@ -27,9 +31,6 @@ export interface TokenColorStyle {
|
|||
fontStyle: "bold" | "italic" | "bold italic"
|
||||
}
|
||||
|
||||
import { Configuration, IConfigurationValues } from "./Configuration"
|
||||
import { ThemeManager } from "./Themes"
|
||||
|
||||
export class TokenColors implements IDisposable {
|
||||
private _subscriptions: IDisposable[] = []
|
||||
private _tokenColors: TokenColor[] = []
|
||||
|
@ -71,38 +72,49 @@ export class TokenColors implements IDisposable {
|
|||
this._subscriptions = []
|
||||
}
|
||||
|
||||
private _flattenThemeTokens = (themeTokens: ThemeToken[] = []) => {
|
||||
const multidimensionalTokens = themeTokens.map(token => {
|
||||
if (Array.isArray(token.scope)) {
|
||||
return token.scope.map(s => ({
|
||||
scope: s,
|
||||
settings: token.settings,
|
||||
}))
|
||||
}
|
||||
return token
|
||||
})
|
||||
return [].concat(...multidimensionalTokens).filter(t => !!t.scope)
|
||||
}
|
||||
|
||||
private _updateTokenColors(): void {
|
||||
const {
|
||||
activeTheme: {
|
||||
colors: { "editor.tokenColors": tokenColorsFromTheme = [] },
|
||||
colors: { "editor.tokenColors": themeTokens = [] },
|
||||
},
|
||||
} = this._themeManager
|
||||
|
||||
const themeTokens = this._flattenThemeTokens(tokenColorsFromTheme)
|
||||
const userColors = this._configuration.getValue("editor.tokenColors")
|
||||
|
||||
this._tokenColors = this._mergeTokenColors({
|
||||
const combinedColors = this._mergeTokenColors({
|
||||
user: userColors,
|
||||
theme: themeTokens,
|
||||
defaults: this._defaultTokenColors,
|
||||
})
|
||||
|
||||
this._tokenColors = this._convertThemeTokenScopes(combinedColors)
|
||||
|
||||
this._onTokenColorsChangedEvent.dispatch()
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme tokens can pass in token scopes as a string or an array
|
||||
* this converts all token scopes passed in to an array of strings
|
||||
*
|
||||
* @name convertThemeTokenScopes
|
||||
* @function
|
||||
* @param {ThemeToken[]} tokens
|
||||
* @returns {TokenColor[]}
|
||||
*/
|
||||
private _convertThemeTokenScopes(tokens: ThemeToken[]) {
|
||||
// TODO: figure out how space separated token scopes should be handled
|
||||
// token.scope.split(" ") -> convert "meta.var string.quoted" -> ["meta.var", "string.quoted"]
|
||||
// this however breaks prioritisation of tokens
|
||||
return tokens.map(token => {
|
||||
const scope = !token.scope
|
||||
? []
|
||||
: Array.isArray(token.scope)
|
||||
? token.scope
|
||||
: [token.scope]
|
||||
return { ...token, scope }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge different token source whilst unifying settings
|
||||
* each source is passed by name so that later the priority
|
||||
|
@ -111,34 +123,32 @@ export class TokenColors implements IDisposable {
|
|||
* user source
|
||||
*/
|
||||
private _mergeTokenColors(tokens: {
|
||||
user: TokenColor[]
|
||||
user: ThemeToken[]
|
||||
defaults: TokenColor[]
|
||||
theme: TokenColor[]
|
||||
theme: ThemeToken[]
|
||||
}) {
|
||||
return Object.keys(tokens).reduce(
|
||||
(output, key) => {
|
||||
const tokenColors: TokenColor[] = tokens[key]
|
||||
return tokenColors.reduce((mergedTokens, currentToken) => {
|
||||
return Object.entries(tokens).reduce<ThemeToken[]>(
|
||||
(output, [_source, tokenColors]) =>
|
||||
tokenColors.reduce((mergedTokens, currentToken) => {
|
||||
const duplicateToken = mergedTokens.find(t => currentToken.scope === t.scope)
|
||||
if (duplicateToken) {
|
||||
return mergedTokens.map(existingToken => {
|
||||
if (existingToken.scope === duplicateToken.scope) {
|
||||
return this._mergeSettings(existingToken, {
|
||||
...currentToken,
|
||||
_source: key,
|
||||
_source,
|
||||
})
|
||||
}
|
||||
return existingToken
|
||||
})
|
||||
}
|
||||
return [...mergedTokens, { ...currentToken, _source: key }]
|
||||
}, output)
|
||||
},
|
||||
[] as TokenColor[],
|
||||
return [...mergedTokens, { ...currentToken, _source }]
|
||||
}, output),
|
||||
[],
|
||||
)
|
||||
}
|
||||
|
||||
private _mergeSettings(prev: TokenColor, next: TokenColor) {
|
||||
private _mergeSettings(prev: ThemeToken, next: ThemeToken) {
|
||||
const priority = {
|
||||
user: 2,
|
||||
theme: 1,
|
||||
|
|
|
@ -26,7 +26,7 @@ import * as Helpers from "./../../Plugins/Api/LanguageClient/LanguageClientHelpe
|
|||
|
||||
import { Configuration } from "./../Configuration"
|
||||
import { EditorManager } from "./../EditorManager"
|
||||
import { convertTextDocumentEditsToFileMap } from "./../Language/Edits"
|
||||
import { convertTextDocumentChangesToFileMap } from "./../Language/Edits"
|
||||
|
||||
import { WorkspaceConfiguration } from "./WorkspaceConfiguration"
|
||||
|
||||
|
@ -71,10 +71,9 @@ export class Workspace implements Oni.Workspace.Api {
|
|||
}
|
||||
|
||||
public async applyEdits(edits: types.WorkspaceEdit): Promise<void> {
|
||||
let editsToUse = edits
|
||||
if (edits.documentChanges) {
|
||||
editsToUse = convertTextDocumentEditsToFileMap(edits.documentChanges)
|
||||
}
|
||||
const editsToUse = edits.documentChanges
|
||||
? convertTextDocumentChangesToFileMap(edits.documentChanges)
|
||||
: edits.changes
|
||||
|
||||
const files = Object.keys(editsToUse)
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ const TabsWrapper = styled<ITabsWrapperProps, "div">("div")`
|
|||
align-items: flex-end;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
border-bottom: 4px solid ${themeGet("tabs.background")};
|
||||
border-bottom: 4px solid ${themeGet("tabs.borderBottom", "tabs.background")};
|
||||
font-family: ${props => props.fontFamily};
|
||||
font-size: ${props => props.fontSize};
|
||||
transform: translateY(-3px);
|
||||
|
|
|
@ -63,8 +63,6 @@ class WildMenu extends React.Component<Props, State> {
|
|||
currentPage: 1,
|
||||
itemsPerPage: 10,
|
||||
}
|
||||
private selectedElement: HTMLUListElement
|
||||
private containerElement: HTMLUListElement
|
||||
|
||||
public componentWillReceiveProps(next: Props) {
|
||||
if (next.selected !== this.props.selected) {
|
||||
|
@ -80,16 +78,10 @@ class WildMenu extends React.Component<Props, State> {
|
|||
|
||||
return (
|
||||
visible && (
|
||||
<WildMenuList innerRef={e => (this.containerElement = e)}>
|
||||
<WildMenuList>
|
||||
{currentItems &&
|
||||
currentItems.map((option, i) => (
|
||||
<WildMenuItem
|
||||
innerRef={e =>
|
||||
i === current - 1 ? (this.selectedElement = e) : null
|
||||
}
|
||||
selected={i === current}
|
||||
key={option + i}
|
||||
>
|
||||
<WildMenuItem selected={i === current} key={option + i}>
|
||||
<span>
|
||||
<Icon name="file-text" />
|
||||
</span>
|
||||
|
|
|
@ -311,3 +311,8 @@ export function get<T>(obj: T, ...paths: string[]): string {
|
|||
.split(".")
|
||||
.reduce((a, b) => (a && a[b] ? a[b] : null), obj)
|
||||
}
|
||||
|
||||
export function prettyPrint<T extends object>(item: T, spacing = 2) {
|
||||
// tslint:disable-next-line
|
||||
console.log(JSON.stringify(item, null, spacing))
|
||||
}
|
||||
|
|
|
@ -524,8 +524,8 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance {
|
|||
const settings = vimHighlightToTokenColorStyle(currentValue)
|
||||
const newScopeNames: string[] = VimHighlightToDefaultScope[highlightGroupName] || []
|
||||
|
||||
const newScopes = newScopeNames.map((scope): TokenColor => ({
|
||||
scope,
|
||||
const newScopes = newScopeNames.map(scope => ({
|
||||
scope: [scope],
|
||||
settings,
|
||||
}))
|
||||
|
||||
|
|
|
@ -28,42 +28,41 @@ const getGuiStringFromTokenColor = ({ settings: { fontStyle } }: TokenColor): st
|
|||
}
|
||||
|
||||
export class NeovimTokenColorSynchronizer {
|
||||
private _currentIndex: number = 0
|
||||
private _currentIndex = 0
|
||||
private _tokenScopeSelectorToHighlightName: { [key: string]: string } = {}
|
||||
private _highlightNameToHighlightValue: { [key: string]: string } = {}
|
||||
private _highlightNameToHighlightValue = new Map<string, string>()
|
||||
|
||||
constructor(private _neovimInstance: NeovimInstance) {}
|
||||
constructor(private _neovimInstance: NeovimInstance) {
|
||||
this._neovimInstance.onColorsChanged.subscribe(this._resetHighlightCache)
|
||||
}
|
||||
|
||||
// This method creates highlight groups for any token colors that haven't been set yet
|
||||
public async synchronizeTokenColors(tokenColors: TokenColor[]): Promise<void> {
|
||||
const highlightsToAdd = tokenColors.map(tokenColor => {
|
||||
public async synchronizeTokenColors(tokenColors: TokenColor[]) {
|
||||
const highlightsToAdd = tokenColors.reduce<string[]>((newHighlights, tokenColor) => {
|
||||
const highlightName = this._getOrCreateHighlightGroup(tokenColor)
|
||||
const highlightFromScope = this._convertTokenStyleToHighlightInfo(tokenColor)
|
||||
|
||||
const currentHighlight = this._highlightNameToHighlightValue[highlightName]
|
||||
const currentHighlight = this._highlightNameToHighlightValue.get(highlightName)
|
||||
|
||||
if (currentHighlight === highlightFromScope) {
|
||||
return null
|
||||
} else {
|
||||
this._highlightNameToHighlightValue[highlightName] = highlightFromScope
|
||||
return highlightFromScope
|
||||
return newHighlights
|
||||
}
|
||||
})
|
||||
this._highlightNameToHighlightValue.set(highlightName, highlightFromScope)
|
||||
return [...newHighlights, highlightFromScope]
|
||||
}, [])
|
||||
|
||||
const filteredHighlights = highlightsToAdd.filter(hl => !!hl)
|
||||
|
||||
const atomicCalls = filteredHighlights.map(hlCommand => ["nvim_command", [hlCommand]])
|
||||
const atomicCalls = highlightsToAdd.map(hlCommand => ["nvim_command", [hlCommand]])
|
||||
|
||||
if (!atomicCalls.length) {
|
||||
return
|
||||
}
|
||||
|
||||
Log.info(
|
||||
"[NeovimTokenColorSynchronizer::synchronizeTokenColors] Setting " +
|
||||
atomicCalls.length +
|
||||
" highlights",
|
||||
`[NeovimTokenColorSynchronizer::synchronizeTokenColors] Setting ${
|
||||
atomicCalls.length
|
||||
} highlights`,
|
||||
)
|
||||
await this._neovimInstance.request("nvim_call_atomic", [atomicCalls])
|
||||
this._neovimInstance.request("nvim_call_atomic", [atomicCalls])
|
||||
Log.info(
|
||||
"[NeovimTokenColorSynchronizer::synchronizeTokenColors] Highlights set successfully",
|
||||
)
|
||||
|
@ -77,6 +76,10 @@ export class NeovimTokenColorSynchronizer {
|
|||
return this._getOrCreateHighlightGroup(tokenColor)
|
||||
}
|
||||
|
||||
private _resetHighlightCache = () => {
|
||||
this._highlightNameToHighlightValue.clear()
|
||||
}
|
||||
|
||||
private _convertTokenStyleToHighlightInfo(tokenColor: TokenColor): string {
|
||||
const name = this._getOrCreateHighlightGroup(tokenColor)
|
||||
const foregroundColor = Color(tokenColor.settings.foreground).hex()
|
||||
|
@ -86,9 +89,9 @@ export class NeovimTokenColorSynchronizer {
|
|||
}
|
||||
|
||||
private _getOrCreateHighlightGroup(tokenColor: TokenColor): string {
|
||||
const existingGroup = this._tokenScopeSelectorToHighlightName[
|
||||
this._getKeyFromTokenColor(tokenColor)
|
||||
]
|
||||
const tokenKey = this._getKeyFromTokenColor(tokenColor)
|
||||
const existingGroup = this._tokenScopeSelectorToHighlightName[tokenKey]
|
||||
|
||||
if (existingGroup) {
|
||||
return existingGroup
|
||||
} else {
|
||||
|
@ -98,21 +101,20 @@ export class NeovimTokenColorSynchronizer {
|
|||
"[NeovimTokenColorSynchronizer::_getOrCreateHighlightGroup] Creating new highlight group - " +
|
||||
newHighlightGroupName,
|
||||
)
|
||||
this._tokenScopeSelectorToHighlightName[
|
||||
this._getKeyFromTokenColor(tokenColor)
|
||||
] = newHighlightGroupName
|
||||
this._tokenScopeSelectorToHighlightName[tokenKey] = newHighlightGroupName
|
||||
return newHighlightGroupName
|
||||
}
|
||||
}
|
||||
|
||||
private _getKeyFromTokenColor(tokenColor: TokenColor): string {
|
||||
const {
|
||||
settings: { background, foreground, fontStyle },
|
||||
settings: { background = "none", foreground = "none", fontStyle = "none" },
|
||||
} = tokenColor
|
||||
const separator = `__`
|
||||
const bg = `background-${background}`
|
||||
const fg = `foreground-${foreground}`
|
||||
const bold = `bold-${fontStyle && fontStyle.includes("bold")}`
|
||||
const italic = `italic-${fontStyle && fontStyle.includes("italic")}`
|
||||
return `${tokenColor.scope}_${bg}_${fg}_${bold}_${italic}`
|
||||
const bold = `bold-${fontStyle ? fontStyle.includes("bold") : false}`
|
||||
const italic = `italic-${fontStyle ? fontStyle.includes("italic") : false}`
|
||||
return [tokenColor.scope, bg, fg, bold, italic].join(separator)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,11 @@ export interface NeovimActiveWindowState {
|
|||
dimensions: Oni.Shapes.Rectangle
|
||||
}
|
||||
|
||||
type Lines = string[]
|
||||
type Height = number
|
||||
type Width = number
|
||||
type WindowPosition = [number, number]
|
||||
|
||||
export interface NeovimInactiveWindowState {
|
||||
windowNumber: number
|
||||
dimensions: Oni.Shapes.Rectangle
|
||||
|
@ -70,6 +75,12 @@ export class NeovimWindowManager extends Utility.Disposable {
|
|||
this._scrollObservable = new Subject<EventContext>()
|
||||
|
||||
const updateScroll = (evt: EventContext) => this._scrollObservable.next(evt)
|
||||
|
||||
const handleCommandLineEvent = async () => {
|
||||
const ctx = await this._neovimInstance.getContext()
|
||||
updateScroll(ctx)
|
||||
}
|
||||
|
||||
// First element of the BufEnter event is the current buffer
|
||||
this.trackDisposable(
|
||||
this._neovimInstance.autoCommands.onBufEnter.subscribe(bufs =>
|
||||
|
@ -88,6 +99,12 @@ export class NeovimWindowManager extends Utility.Disposable {
|
|||
this.trackDisposable(
|
||||
this._neovimInstance.autoCommands.onCursorMoved.subscribe(updateScroll),
|
||||
)
|
||||
this.trackDisposable(
|
||||
this._neovimInstance.onCommandLineShow.subscribe(handleCommandLineEvent),
|
||||
)
|
||||
this.trackDisposable(
|
||||
this._neovimInstance.onCommandLineHide.subscribe(handleCommandLineEvent),
|
||||
)
|
||||
this.trackDisposable(this._neovimInstance.autoCommands.onVimResized.subscribe(updateScroll))
|
||||
this.trackDisposable(this._neovimInstance.onScroll.subscribe(updateScroll))
|
||||
|
||||
|
@ -167,31 +184,38 @@ export class NeovimWindowManager extends Utility.Disposable {
|
|||
currentWinId: number,
|
||||
context: EventContext,
|
||||
): Promise<NeovimActiveWindowState> {
|
||||
const positionCalls = [
|
||||
["nvim_call_function", ["line", ["w0"]]],
|
||||
["nvim_call_function", ["line", ["w$"]]],
|
||||
]
|
||||
// We query the top and bottom line positions again despite these being on the context
|
||||
// as the values from the `BufferUpdate` event can be incorrect
|
||||
const [[topLine, bottomLine]] = await this._neovimInstance.request<[[number, number], any]>(
|
||||
"nvim_call_atomic",
|
||||
[positionCalls],
|
||||
)
|
||||
|
||||
const atomicCalls = [
|
||||
["nvim_win_get_position", [currentWinId]],
|
||||
["nvim_win_get_width", [currentWinId]],
|
||||
["nvim_win_get_height", [currentWinId]],
|
||||
[
|
||||
"nvim_buf_get_lines",
|
||||
[context.bufferNumber, context.windowTopLine - 1, context.windowBottomLine, false],
|
||||
],
|
||||
["nvim_buf_get_lines", [context.bufferNumber, topLine - 1, bottomLine, false]],
|
||||
]
|
||||
|
||||
const response = await this._neovimInstance.request("nvim_call_atomic", [atomicCalls])
|
||||
const response = await this._neovimInstance.request<
|
||||
Array<[WindowPosition, Width, Height, Lines]>
|
||||
>("nvim_call_atomic", [atomicCalls])
|
||||
|
||||
if (!response) {
|
||||
return null
|
||||
}
|
||||
|
||||
const values = response[0]
|
||||
const [values] = response
|
||||
|
||||
if (values.length === 4) {
|
||||
// Grab the results of the `nvim_atomic_call`, as they are returned in an array
|
||||
const position = values[0]
|
||||
const [position, width, height, lines] = values
|
||||
const [row, col] = position
|
||||
const width = values[1]
|
||||
const height = values[2]
|
||||
const lines = values[3]
|
||||
|
||||
// The 'gutterOffset' (difference between `wincol` and `column`) is the size of the gutter
|
||||
// (for example, line numbers). The buffer isn't in that space, so we need to account
|
||||
|
@ -270,10 +294,8 @@ export class NeovimWindowManager extends Utility.Disposable {
|
|||
|
||||
if (values.length === 3) {
|
||||
// Grab the results of the `nvim_atomic_call`, as they are returned in an array
|
||||
const position = values[0]
|
||||
const [position, width, height] = values
|
||||
const [row, col] = position
|
||||
const width = values[1]
|
||||
const height = values[2]
|
||||
|
||||
const dimensions = {
|
||||
x: col,
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
import * as assert from "assert"
|
||||
import * as path from "path"
|
||||
import * as sinon from "sinon"
|
||||
|
||||
import { Event } from "oni-types"
|
||||
import { ErrorCodes } from "vscode-jsonrpc/lib/messages"
|
||||
|
||||
import { Definition } from "../../../src/Editor/NeovimEditor/Definition"
|
||||
import { Symbols } from "../../../src/Editor/NeovimEditor/Symbols"
|
||||
import { wrapPathInFileUri } from "../../../src/Plugins/Api/LanguageClient/LanguageClientHelpers"
|
||||
import { LanguageManager } from "../../../src/Services/Language"
|
||||
import { Menu, MenuManager } from "../../../src/Services/Menu"
|
||||
|
||||
/* tslint:disable:no-string-literal */
|
||||
|
||||
const clock: any = global["clock"] // tslint:disable-line
|
||||
const waitForPromiseResolution: any = global["waitForPromiseResolution"] // tslint:disable-line
|
||||
|
||||
describe("Symbols", () => {
|
||||
let editor: any
|
||||
let definition: any
|
||||
let languageManager: any
|
||||
let menuManager: any
|
||||
let symbols: any
|
||||
|
||||
beforeEach(() => {
|
||||
editor = sinon.stub()
|
||||
editor.activeBuffer = "mock buffer"
|
||||
definition = sinon.createStubInstance(Definition)
|
||||
languageManager = sinon.createStubInstance(LanguageManager)
|
||||
menuManager = sinon.createStubInstance(MenuManager)
|
||||
|
||||
symbols = new Symbols(editor, definition, languageManager, menuManager)
|
||||
})
|
||||
|
||||
describe("open workspace/document menus", () => {
|
||||
let menu: any
|
||||
let onFilterTextChanged: Event<string>
|
||||
let onItemSelected: Event<string>
|
||||
|
||||
beforeEach(() => {
|
||||
menu = sinon.createStubInstance(Menu)
|
||||
onFilterTextChanged = new Event<string>()
|
||||
onItemSelected = new Event<string>()
|
||||
sinon.stub(menu, "onItemSelected").get(() => onItemSelected)
|
||||
sinon.stub(menu, "onFilterTextChanged").get(() => onFilterTextChanged)
|
||||
menuManager.create.returns(menu)
|
||||
|
||||
symbols["_requestSymbols"] = sinon.stub().resolves(["first symbol", "second symbol"])
|
||||
const _symbolInfoToMenuItem = sinon.stub()
|
||||
_symbolInfoToMenuItem.onCall(0).returns("first transformed")
|
||||
_symbolInfoToMenuItem.onCall(1).returns("second transformed")
|
||||
symbols["_symbolInfoToMenuItem"] = _symbolInfoToMenuItem
|
||||
})
|
||||
|
||||
describe("openWorkspaceSymbolsMenu", () => {
|
||||
let getKey: any
|
||||
|
||||
beforeEach(() => {
|
||||
getKey = sinon.stub()
|
||||
symbols["_getDetailFromSymbol"] = sinon.stub().returns(getKey)
|
||||
})
|
||||
|
||||
it("requests workspace symbols when filter text is changed", async () => {
|
||||
// setup
|
||||
symbols.openWorkspaceSymbolsMenu()
|
||||
clock.tick(30)
|
||||
sinon.assert.notCalled(symbols["_requestSymbols"])
|
||||
|
||||
// action
|
||||
onFilterTextChanged.dispatch("mock query")
|
||||
|
||||
// confirm
|
||||
clock.tick(24)
|
||||
sinon.assert.notCalled(symbols["_requestSymbols"])
|
||||
clock.tick(1)
|
||||
sinon.assert.calledWithExactly(
|
||||
symbols["_requestSymbols"],
|
||||
"mock buffer",
|
||||
"workspace/symbol",
|
||||
menu,
|
||||
{ query: "mock query" },
|
||||
)
|
||||
await waitForPromiseResolution()
|
||||
assertCommon()
|
||||
})
|
||||
})
|
||||
|
||||
describe("openDocumentSymbolsMenu", () => {
|
||||
it("requests document symbols when completion menu is opened", async () => {
|
||||
// action
|
||||
await symbols.openDocumentSymbolsMenu()
|
||||
|
||||
// confirm
|
||||
sinon.assert.calledWithExactly(
|
||||
symbols["_requestSymbols"],
|
||||
"mock buffer",
|
||||
"textDocument/documentSymbol",
|
||||
menu,
|
||||
)
|
||||
assertCommon()
|
||||
})
|
||||
})
|
||||
|
||||
const assertCommon = () => {
|
||||
assert.deepEqual(symbols["_symbolInfoToMenuItem"].args, [
|
||||
["first symbol"],
|
||||
["second symbol"],
|
||||
])
|
||||
sinon.assert.calledWithExactly(menu.setItems.lastCall, [
|
||||
"first transformed",
|
||||
"second transformed",
|
||||
])
|
||||
}
|
||||
}) // End describe open menus
|
||||
|
||||
describe("_requestSymbols", () => {
|
||||
let menu: any
|
||||
let buffer: any
|
||||
|
||||
beforeEach(() => {
|
||||
menu = sinon.createStubInstance(Menu)
|
||||
menu.isOpen.returns(true)
|
||||
buffer = sinon.stub()
|
||||
buffer.language = "mocklang"
|
||||
buffer.filePath = path.join("mock", "path")
|
||||
})
|
||||
|
||||
it("throws on unknown errors", async () => {
|
||||
// setup
|
||||
const error = new Error()
|
||||
languageManager.sendLanguageServerRequest.throws(error)
|
||||
|
||||
try {
|
||||
// action
|
||||
await symbols["_requestSymbols"](buffer, "mock command", menu)
|
||||
|
||||
// confirm
|
||||
assert.fail("Expected exception to be thrown")
|
||||
} catch (e) {
|
||||
assert.strictEqual(e, error)
|
||||
}
|
||||
})
|
||||
|
||||
it("retries whilst server is initialising", async () => {
|
||||
// setup
|
||||
const error: any = new Error()
|
||||
error.code = ErrorCodes.ServerNotInitialized
|
||||
languageManager.sendLanguageServerRequest.onCall(0).throws(error)
|
||||
languageManager.sendLanguageServerRequest.onCall(1).throws(error)
|
||||
languageManager.sendLanguageServerRequest.onCall(2).returns("mock result")
|
||||
|
||||
// action
|
||||
const request: Promise<any> = symbols["_requestSymbols"](buffer, "mock command", menu, {
|
||||
mock: "option",
|
||||
})
|
||||
|
||||
// confirm
|
||||
sinon.assert.callCount(languageManager.sendLanguageServerRequest, 1)
|
||||
clock.tick(999)
|
||||
await waitForPromiseResolution()
|
||||
sinon.assert.callCount(languageManager.sendLanguageServerRequest, 1)
|
||||
clock.tick(1)
|
||||
await waitForPromiseResolution()
|
||||
sinon.assert.callCount(languageManager.sendLanguageServerRequest, 2)
|
||||
clock.tick(1000)
|
||||
await waitForPromiseResolution()
|
||||
sinon.assert.callCount(languageManager.sendLanguageServerRequest, 3)
|
||||
clock.tick(1000)
|
||||
await waitForPromiseResolution()
|
||||
sinon.assert.callCount(languageManager.sendLanguageServerRequest, 3)
|
||||
clock.tick(1000)
|
||||
await waitForPromiseResolution()
|
||||
sinon.assert.alwaysCalledWith(
|
||||
languageManager.sendLanguageServerRequest,
|
||||
"mocklang",
|
||||
buffer.filePath,
|
||||
"mock command",
|
||||
{ mock: "option", textDocument: { uri: wrapPathInFileUri(buffer.filePath) } },
|
||||
)
|
||||
assert.equal(await request, "mock result")
|
||||
})
|
||||
|
||||
it("gives up retrying if menu is closed", async () => {
|
||||
// setup
|
||||
const error: any = new Error()
|
||||
error.code = ErrorCodes.ServerNotInitialized
|
||||
languageManager.sendLanguageServerRequest.throws(error)
|
||||
|
||||
// action
|
||||
const request: Promise<any> = symbols["_requestSymbols"](buffer, "mock command", menu)
|
||||
|
||||
// confirm
|
||||
sinon.assert.callCount(languageManager.sendLanguageServerRequest, 1)
|
||||
clock.tick(1000)
|
||||
await waitForPromiseResolution()
|
||||
sinon.assert.callCount(languageManager.sendLanguageServerRequest, 2)
|
||||
menu.isOpen.returns(false)
|
||||
clock.tick(1000)
|
||||
await waitForPromiseResolution()
|
||||
sinon.assert.callCount(languageManager.sendLanguageServerRequest, 2)
|
||||
|
||||
const result = await request
|
||||
|
||||
assert.deepEqual(result, [])
|
||||
})
|
||||
})
|
||||
})
|
|
@ -16,6 +16,12 @@ export class MockNeovimInstance {
|
|||
private _requests: NeovimRequest[] = []
|
||||
private _pendingPromises: Array<Utility.ICompletablePromise<any>> = []
|
||||
|
||||
public get onColorsChanged() {
|
||||
return {
|
||||
subscribe: (fn: (args?: any) => any) => fn(),
|
||||
}
|
||||
}
|
||||
|
||||
public request(requestName: string, args: any[]) {
|
||||
this._requests.push({ requestName, args })
|
||||
const promise = Utility.createCompletablePromise()
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import * as assert from "assert"
|
||||
import { CompletionItem } from "vscode-languageserver-types"
|
||||
|
||||
import { filterCompletionOptions } from "../../../src/Services/Completion/CompletionSelectors"
|
||||
|
||||
describe("filterCompletionOptions", () => {
|
||||
it("strips duplicates and sorts in order of abbreviation=>label=>sortText", () => {
|
||||
const item1: CompletionItem = {
|
||||
label: "mock duplicate",
|
||||
detail: "mock detail",
|
||||
sortText: "c",
|
||||
}
|
||||
const item2: CompletionItem = {
|
||||
label: "mock duplicate",
|
||||
detail: "mock detail",
|
||||
sortText: "b",
|
||||
}
|
||||
const item3: CompletionItem = {
|
||||
label: "mock duplicate",
|
||||
detail: "mock not duplicate detail",
|
||||
sortText: "a",
|
||||
}
|
||||
const item4: CompletionItem = {
|
||||
label: "maaaaoaaaacaaaak abbreviation",
|
||||
}
|
||||
const item5: CompletionItem = {
|
||||
label: "mock cherry",
|
||||
filterText: "mock cherry",
|
||||
}
|
||||
const item6: CompletionItem = {
|
||||
label: "mock cherry",
|
||||
filterText: "mock banana",
|
||||
}
|
||||
const item7: CompletionItem = {
|
||||
label: "mock apple",
|
||||
}
|
||||
const item8: CompletionItem = {
|
||||
label: "doesnt match",
|
||||
}
|
||||
const item9: CompletionItem = {
|
||||
label: "mock apple",
|
||||
filterText: "doesnt match either",
|
||||
}
|
||||
const items: CompletionItem[] = [
|
||||
item1,
|
||||
item2,
|
||||
item3,
|
||||
item4,
|
||||
item5,
|
||||
item6,
|
||||
item7,
|
||||
item8,
|
||||
item9,
|
||||
]
|
||||
|
||||
const filteredItems = filterCompletionOptions(items, "mock")
|
||||
|
||||
assert.deepStrictEqual(filteredItems, [item7, item6, item5, item3, item2, item4])
|
||||
})
|
||||
})
|
|
@ -0,0 +1,66 @@
|
|||
import * as assert from "assert"
|
||||
import * as _ from "lodash"
|
||||
|
||||
import { DefaultCompletionResults } from "./../../../src/Services/Completion/CompletionState"
|
||||
import { completionResultsReducer } from "./../../../src/Services/Completion/CompletionStore"
|
||||
|
||||
describe("completionResultsReducer", () => {
|
||||
let oldState: any
|
||||
|
||||
beforeEach(() => {
|
||||
oldState = _.cloneDeep(DefaultCompletionResults)
|
||||
})
|
||||
|
||||
describe("GET_COMPLETION_ITEM_DETAILS_RESULT", () => {
|
||||
beforeEach(() => {
|
||||
oldState.completions = [
|
||||
{ label: "other" },
|
||||
{ label: "matchme", detail: "matchme(signature)" },
|
||||
{ label: "matchme", detail: "other(signature)" },
|
||||
{ label: "matchme" },
|
||||
]
|
||||
})
|
||||
|
||||
it("updates relevant items with detailed version by label field", () => {
|
||||
const completionItemWithDetails = {
|
||||
label: "matchme",
|
||||
}
|
||||
|
||||
const newState = completionResultsReducer(oldState, {
|
||||
type: "GET_COMPLETION_ITEM_DETAILS_RESULT",
|
||||
completionItemWithDetails,
|
||||
})
|
||||
|
||||
assert.deepStrictEqual(newState, {
|
||||
...oldState,
|
||||
completions: [
|
||||
{ label: "other" },
|
||||
completionItemWithDetails,
|
||||
completionItemWithDetails,
|
||||
completionItemWithDetails,
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
it("updates relevant items with detailed version by detail field", () => {
|
||||
const completionItemWithDetails = {
|
||||
label: "matchme",
|
||||
detail: "matchme(signature)",
|
||||
}
|
||||
const newState = completionResultsReducer(oldState, {
|
||||
type: "GET_COMPLETION_ITEM_DETAILS_RESULT",
|
||||
completionItemWithDetails,
|
||||
})
|
||||
|
||||
assert.deepStrictEqual(newState, {
|
||||
...oldState,
|
||||
completions: [
|
||||
{ label: "other" },
|
||||
completionItemWithDetails,
|
||||
{ label: "matchme", detail: "other(signature)" },
|
||||
completionItemWithDetails,
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,60 @@
|
|||
import * as assert from "assert"
|
||||
import * as sinon from "sinon"
|
||||
|
||||
import { LanguageServiceCompletionsRequestor } from "./../../../src/Services/Completion/CompletionsRequestor"
|
||||
import { LanguageManager } from "./../../../src/Services/Language"
|
||||
|
||||
describe("LanguageServiceCompletionsRequestor", () => {
|
||||
describe("getCompletionDetails", () => {
|
||||
let completionItem: any
|
||||
let completionDetails: any
|
||||
let languageManager: any
|
||||
let requestor: any
|
||||
|
||||
beforeEach(() => {
|
||||
completionItem = sinon.stub()
|
||||
completionDetails = sinon.stub()
|
||||
languageManager = sinon.createStubInstance(LanguageManager)
|
||||
languageManager.sendLanguageServerRequest.resolves(completionDetails)
|
||||
requestor = new LanguageServiceCompletionsRequestor(languageManager)
|
||||
})
|
||||
|
||||
it("doesn't send the request if the server is incapable", async () => {
|
||||
languageManager.getCapabilitiesForLanguage.resolves({
|
||||
completionProvider: { resolveProvider: false },
|
||||
})
|
||||
|
||||
const returnedDetails = await requestor.getCompletionDetails(
|
||||
"mocklang",
|
||||
"mockpath",
|
||||
completionItem as any,
|
||||
)
|
||||
|
||||
sinon.assert.calledWithExactly(languageManager.getCapabilitiesForLanguage, "mocklang")
|
||||
sinon.assert.notCalled(languageManager.sendLanguageServerRequest)
|
||||
assert.strictEqual(returnedDetails, completionItem)
|
||||
})
|
||||
|
||||
it("requests completion details if server is capable", async () => {
|
||||
languageManager.getCapabilitiesForLanguage.resolves({
|
||||
completionProvider: { resolveProvider: true },
|
||||
})
|
||||
|
||||
const returnedDetails = await requestor.getCompletionDetails(
|
||||
"mocklang",
|
||||
"mockpath",
|
||||
completionItem as any,
|
||||
)
|
||||
|
||||
sinon.assert.calledWithExactly(languageManager.getCapabilitiesForLanguage, "mocklang")
|
||||
sinon.assert.calledWithExactly(
|
||||
languageManager.sendLanguageServerRequest,
|
||||
"mocklang",
|
||||
"mockpath",
|
||||
"completionItem/resolve",
|
||||
completionItem,
|
||||
)
|
||||
assert.strictEqual(returnedDetails, completionDetails)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,48 @@
|
|||
import * as assert from "assert"
|
||||
import * as sinon from "sinon"
|
||||
|
||||
import { createReducer } from "../../../src/Services/Menu/MenuReducer"
|
||||
import { createDefaultState } from "../../../src/Services/Menu/MenuState"
|
||||
|
||||
describe("MenuReducer", () => {
|
||||
let reducer: any
|
||||
let oldState: any
|
||||
|
||||
beforeEach(() => {
|
||||
reducer = createReducer<any, any>()
|
||||
oldState = createDefaultState<any, any>()
|
||||
oldState.menu = {}
|
||||
})
|
||||
|
||||
describe("popupMenuReducer", () => {
|
||||
describe("FILTER_MENU", () => {
|
||||
let filteredOptions: any
|
||||
let filterFunction: any
|
||||
|
||||
beforeEach(() => {
|
||||
filteredOptions = {}
|
||||
filterFunction = sinon.stub().returns(filteredOptions)
|
||||
oldState.menu.filterFunction = filterFunction
|
||||
})
|
||||
|
||||
it("resets selectedIndex to zero", () => {
|
||||
oldState.menu.selectedIndex = 123
|
||||
|
||||
const newState = reducer(oldState, {
|
||||
type: "FILTER_MENU",
|
||||
payload: { filter: "mock filter" },
|
||||
})
|
||||
|
||||
assert.deepStrictEqual(newState, {
|
||||
...oldState,
|
||||
menu: {
|
||||
filter: "mock filter",
|
||||
filterFunction,
|
||||
filteredOptions,
|
||||
selectedIndex: 0,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -25,7 +25,7 @@ describe("SyntaxHighlightReconciler", () => {
|
|||
|
||||
mockTokenColors = new Mocks.MockTokenColors([
|
||||
{
|
||||
scope: "scope.test",
|
||||
scope: ["scope.test"],
|
||||
settings: {
|
||||
background: COLOR_BLACK,
|
||||
foreground: COLOR_WHITE,
|
||||
|
@ -90,7 +90,7 @@ describe("SyntaxHighlightReconciler", () => {
|
|||
{
|
||||
range: types.Range.create(0, 0, 0, 5),
|
||||
tokenColor: {
|
||||
scope: "scope.test",
|
||||
scope: ["scope.test"],
|
||||
settings: {
|
||||
background: COLOR_BLACK,
|
||||
foreground: COLOR_WHITE,
|
||||
|
@ -151,7 +151,7 @@ describe("SyntaxHighlightReconciler", () => {
|
|||
{
|
||||
range: types.Range.create(0, 0, 0, 5),
|
||||
tokenColor: {
|
||||
scope: "scope.test",
|
||||
scope: ["scope.test"],
|
||||
settings: {
|
||||
background: COLOR_BLACK,
|
||||
foreground: COLOR_WHITE,
|
||||
|
|
|
@ -9,7 +9,7 @@ import { TokenColor } from "./../../src/Services/TokenColors"
|
|||
|
||||
import { MockNeovimInstance } from "./../Mocks/neovim"
|
||||
|
||||
const createTokenColor = (scope: string): TokenColor => ({
|
||||
const createTokenColor = (...scope: string[]): TokenColor => ({
|
||||
scope,
|
||||
settings: {
|
||||
foreground: "#FFFFFF",
|
||||
|
|
|
@ -343,13 +343,18 @@ export class QuickOpen {
|
|||
|
||||
private getDefaultOpenMode(): Oni.FileOpenMode {
|
||||
const legacy = this._oni.configuration.getValue("editor.quickOpen.defaultOpenMode", null)
|
||||
if (legacy) {
|
||||
// the value of the defaultOpenMode is a numerical enum that includes 0 so we check that the value
|
||||
// is a number and that number is an option in the file open mode enum
|
||||
if (!isNaN(legacy) && legacy in Oni.FileOpenMode) {
|
||||
return legacy
|
||||
}
|
||||
return this._oni.configuration.getValue(
|
||||
|
||||
const defaultOpenMode = this._oni.configuration.getValue(
|
||||
"quickOpen.defaultOpenMode",
|
||||
Oni.FileOpenMode.NewTab,
|
||||
)
|
||||
|
||||
return defaultOpenMode
|
||||
}
|
||||
|
||||
private isInstallDirectoryOrHome() {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
|
@ -3,7 +3,7 @@
|
|||
"author": "",
|
||||
"email": "bryphe@outlook.com",
|
||||
"homepage": "https://www.onivim.io",
|
||||
"version": "0.3.7",
|
||||
"version": "0.3.8",
|
||||
"description": "Code editor with a modern twist on modal editing - powered by neovim.",
|
||||
"keywords": [
|
||||
"vim",
|
||||
|
@ -873,7 +873,7 @@
|
|||
"msgpack-lite": "0.1.26",
|
||||
"ocaml-language-server": "^1.0.27",
|
||||
"oni-api": "0.0.49",
|
||||
"oni-fontkit": "^0.0.4",
|
||||
"oni-fontkit": "^0.0.5",
|
||||
"oni-neovim-binaries": "0.1.3",
|
||||
"oni-ripgrep": "0.0.4",
|
||||
"oni-types": "^0.0.8",
|
||||
|
@ -882,16 +882,16 @@
|
|||
"react-dnd-html5-backend": "^2.5.4",
|
||||
"react-dom": "^16.3.2",
|
||||
"redux-batched-subscribe": "^0.1.6",
|
||||
"shell-env": "^0.3.0",
|
||||
"shell-env": "^2.1.0",
|
||||
"shelljs": "0.7.7",
|
||||
"simple-git": "^1.92.0",
|
||||
"styled-components": "^3.4.4",
|
||||
"typescript": "^2.8.1",
|
||||
"typescript": "^3.1.1",
|
||||
"vscode-css-languageserver-bin": "^1.2.1",
|
||||
"vscode-html-languageserver-bin": "^1.1.0",
|
||||
"vscode-jsonrpc": "3.5.0",
|
||||
"vscode-languageserver": "3.5.0",
|
||||
"vscode-languageserver-types": "3.5.0",
|
||||
"vscode-languageserver-types": "3.13.0",
|
||||
"vscode-textmate": "3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -928,7 +928,7 @@
|
|||
"@types/redux-mock-store": "^1.0.0",
|
||||
"@types/rimraf": "^2.0.2",
|
||||
"@types/shelljs": "^0.7.7",
|
||||
"@types/sinon": "1.16.32",
|
||||
"@types/sinon": "5.0.5",
|
||||
"@types/webgl2": "^0.0.3",
|
||||
"autoprefixer": "6.4.0",
|
||||
"aws-sdk": "^2.202.0",
|
||||
|
@ -944,7 +944,7 @@
|
|||
"detect-indent": "^5.0.0",
|
||||
"electron": "2.0.8",
|
||||
"electron-builder": "^20.5.1",
|
||||
"electron-devtools-installer": "^2.2.3",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"electron-mocha": "5.0.0",
|
||||
"electron-rebuild": "^1.7.3",
|
||||
"enzyme": "^3.3.0",
|
||||
|
@ -992,13 +992,13 @@
|
|||
"remap-istanbul": "^0.10.1",
|
||||
"reselect": "3.0.1",
|
||||
"rxjs": "5.5.8",
|
||||
"sinon": "1.17.6",
|
||||
"sinon": "5.0.5",
|
||||
"spectron": "^3.8.0",
|
||||
"style-loader": "0.18.2",
|
||||
"sudo-prompt": "7.1.1",
|
||||
"ts-jest": "^23.0.0",
|
||||
"ts-loader": "^4.2.0",
|
||||
"tslint": "5.9.1",
|
||||
"tslint": "^5.11.0",
|
||||
"typescript-plugin-styled-components": "^0.0.6",
|
||||
"vscode-snippet-parser": "0.0.5",
|
||||
"wcwidth": "1.0.1",
|
||||
|
|
|
@ -18,7 +18,7 @@ export const test = async (oni: Oni.Plugin.Api) => {
|
|||
oni.automation.sendKeys("window.a")
|
||||
|
||||
// Wait for completion popup to show
|
||||
await oni.automation.waitFor(() => getCompletionElement() !== null)
|
||||
await oni.automation.waitFor(() => getCompletionElement() !== null, 120000)
|
||||
|
||||
// Check for 'alert' as an available completion
|
||||
const completionElement = getCompletionElement()
|
||||
|
|
|
@ -44,7 +44,7 @@ export const test = async (oni: Oni.Plugin.Api) => {
|
|||
const hasCompletionElement = () =>
|
||||
getCompletionElement() && getCompletionElement().textContent.indexOf("automation") >= 0
|
||||
|
||||
await oni.automation.waitFor(hasCompletionElement)
|
||||
await oni.automation.waitFor(hasCompletionElement, 120000)
|
||||
|
||||
assert.ok(hasCompletionElement(), "Got completion element!")
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ export const test = async (oni: Oni.Plugin.Api) => {
|
|||
errors[filePath]["language-typescript"] &&
|
||||
errors[filePath]["language-typescript"].length === 3
|
||||
)
|
||||
})
|
||||
}, 120000)
|
||||
|
||||
// nextError jumps to 1st error
|
||||
oni.commands.executeCommand("oni.editor.nextError")
|
||||
|
|
|
@ -29,7 +29,7 @@ export const test = async (oni: Oni.Plugin.Api) => {
|
|||
types.Position.create(0, 0),
|
||||
)
|
||||
return tokens && tokens.scopes && tokens.scopes.length > 0
|
||||
}, 10000)
|
||||
}, 120000)
|
||||
|
||||
oni.automation.sendKeys("w")
|
||||
|
||||
|
@ -37,7 +37,7 @@ export const test = async (oni: Oni.Plugin.Api) => {
|
|||
await oni.automation.waitFor(() => {
|
||||
element = getElementByClassName("quick-info-debug-scopes")
|
||||
return !!element
|
||||
})
|
||||
}, 120000)
|
||||
|
||||
await oni.automation.waitFor(() => {
|
||||
const items = element.getElementsByTagName("li")
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
"check-format"
|
||||
],
|
||||
"whitespace": false,
|
||||
"no-trailing-whitespace": [true, "ignore-template-strings"],
|
||||
"trailing-comma": [
|
||||
true,
|
||||
{
|
||||
|
|
|
@ -93,7 +93,7 @@ declare var require: any
|
|||
const tagsToCollect = ["a", "input", "textarea"]
|
||||
|
||||
tagsToCollect.forEach(tag => {
|
||||
const elems = document.getElementsByTagName(tag) as NodeListOf<HTMLElement>
|
||||
const elems = document.getElementsByTagName(tag) as HTMLCollectionOf<HTMLElement>
|
||||
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
addElement(elems[i])
|
||||
|
|
217
yarn.lock
217
yarn.lock
|
@ -50,6 +50,24 @@
|
|||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
|
||||
|
||||
"@sinonjs/formatio@3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-3.0.0.tgz#9d282d81030a03a03fa0c5ce31fd8786a4da311a"
|
||||
dependencies:
|
||||
"@sinonjs/samsam" "2.1.0"
|
||||
|
||||
"@sinonjs/formatio@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-2.0.0.tgz#84db7e9eb5531df18a8c5e0bfb6e449e55e654b2"
|
||||
dependencies:
|
||||
samsam "1.3.0"
|
||||
|
||||
"@sinonjs/samsam@2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-2.1.0.tgz#b8b8f5b819605bd63601a6ede459156880f38ea3"
|
||||
dependencies:
|
||||
array-from "^2.1.1"
|
||||
|
||||
"@types/cheerio@*":
|
||||
version "0.22.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce"
|
||||
|
@ -269,9 +287,9 @@
|
|||
"@types/glob" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/sinon@1.16.32":
|
||||
version "1.16.32"
|
||||
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-1.16.32.tgz#b3246844902d7cb33f376b369b176a65a144af7e"
|
||||
"@types/sinon@5.0.5":
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-5.0.5.tgz#de600fa07eb1ec9d5f55669d5bac46a75fc88115"
|
||||
|
||||
"@types/tough-cookie@*":
|
||||
version "2.3.2"
|
||||
|
@ -630,6 +648,10 @@ array-flatten@^2.1.0:
|
|||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296"
|
||||
|
||||
array-from@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195"
|
||||
|
||||
array-includes@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d"
|
||||
|
@ -2304,8 +2326,8 @@ class-utils@^0.3.5:
|
|||
static-extend "^0.1.1"
|
||||
|
||||
classnames@^2.2.3, classnames@^2.2.5:
|
||||
version "2.2.5"
|
||||
resolved "https://codeload.github.com/JedWatson/classnames/tar.gz/34a05a53d31d35879ec7088949ae5a1b2224043a"
|
||||
version "2.2.6"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||
|
||||
clean-css@4.1.x:
|
||||
version "4.1.11"
|
||||
|
@ -2816,7 +2838,7 @@ cross-spawn@^3.0.1:
|
|||
lru-cache "^4.0.1"
|
||||
which "^1.2.9"
|
||||
|
||||
cross-spawn@^4, cross-spawn@^4.0.0:
|
||||
cross-spawn@^4:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41"
|
||||
dependencies:
|
||||
|
@ -2831,7 +2853,7 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0:
|
|||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
cross-spawn@^6.0.4, cross-spawn@^6.0.5:
|
||||
cross-spawn@^6.0.0, cross-spawn@^6.0.4, cross-spawn@^6.0.5:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
dependencies:
|
||||
|
@ -3133,7 +3155,7 @@ default-require-extensions@^2.0.0:
|
|||
dependencies:
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
default-shell@^1.0.0:
|
||||
default-shell@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/default-shell/-/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc"
|
||||
|
||||
|
@ -3249,14 +3271,14 @@ diff@3.3.1:
|
|||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75"
|
||||
|
||||
diff@^3.1.0, diff@^3.3.1, diff@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
|
||||
|
||||
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"
|
||||
|
@ -3923,18 +3945,6 @@ exec-sh@^0.2.0:
|
|||
dependencies:
|
||||
merge "^1.1.3"
|
||||
|
||||
execa@^0.5.0:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-0.5.1.tgz#de3fb85cb8d6e91c85bcbceb164581785cb57b36"
|
||||
dependencies:
|
||||
cross-spawn "^4.0.0"
|
||||
get-stream "^2.2.0"
|
||||
is-stream "^1.1.0"
|
||||
npm-run-path "^2.0.0"
|
||||
p-finally "^1.0.0"
|
||||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
execa@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
|
||||
|
@ -3959,6 +3969,18 @@ execa@^0.8.0:
|
|||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
execa@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
|
||||
dependencies:
|
||||
cross-spawn "^6.0.0"
|
||||
get-stream "^4.0.0"
|
||||
is-stream "^1.1.0"
|
||||
npm-run-path "^2.0.0"
|
||||
p-finally "^1.0.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"
|
||||
|
@ -4368,12 +4390,6 @@ form-data@~2.3.1:
|
|||
combined-stream "^1.0.5"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formatio@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.1.1.tgz#5ed3ccd636551097383465d996199100e86161e9"
|
||||
dependencies:
|
||||
samsam "~1.1"
|
||||
|
||||
forwarded@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||
|
@ -4539,12 +4555,11 @@ 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"
|
||||
get-stream@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
||||
dependencies:
|
||||
object-assign "^4.0.1"
|
||||
pinkie-promise "^2.0.0"
|
||||
pump "^3.0.0"
|
||||
|
||||
get-value@^2.0.3, get-value@^2.0.6:
|
||||
version "2.0.6"
|
||||
|
@ -6466,6 +6481,10 @@ jsprim@^1.2.2:
|
|||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
just-extend@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-3.0.0.tgz#cee004031eaabf6406da03a7b84e4fe9d78ef288"
|
||||
|
||||
keyboard-layout@^2.0.13:
|
||||
version "2.0.13"
|
||||
resolved "https://registry.yarnpkg.com/keyboard-layout/-/keyboard-layout-2.0.13.tgz#5b4f5c25835e5d221a7b9da897663100d897487d"
|
||||
|
@ -6812,14 +6831,14 @@ lokijs@1.5.2:
|
|||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.2.tgz#75d43df21232f1d5479d191a69b6ebf61754a873"
|
||||
|
||||
lolex@1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31"
|
||||
|
||||
lolex@2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.3.1.tgz#3d2319894471ea0950ef64692ead2a5318cff362"
|
||||
|
||||
lolex@^2.2.0, lolex@^2.3.2:
|
||||
version "2.7.5"
|
||||
resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.7.5.tgz#113001d56bfc7e02d56e36291cc5c413d1aa0733"
|
||||
|
||||
longest@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
||||
|
@ -7315,6 +7334,16 @@ nice-try@^1.0.4:
|
|||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"
|
||||
|
||||
nise@^1.2.0:
|
||||
version "1.4.5"
|
||||
resolved "https://registry.yarnpkg.com/nise/-/nise-1.4.5.tgz#979a97a19c48d627bb53703726ae8d53ce8d4b3e"
|
||||
dependencies:
|
||||
"@sinonjs/formatio" "3.0.0"
|
||||
just-extend "^3.0.0"
|
||||
lolex "^2.3.2"
|
||||
path-to-regexp "^1.7.0"
|
||||
text-encoding "^0.6.4"
|
||||
|
||||
no-case@^2.2.0:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
|
||||
|
@ -7725,9 +7754,9 @@ oni-core-logging@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/oni-core-logging/-/oni-core-logging-1.0.0.tgz#7ad6c0ad8b06c23255202f97e229c2b0947dcf0b"
|
||||
|
||||
oni-fontkit@^0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/oni-fontkit/-/oni-fontkit-0.0.4.tgz#4bc91a2c9802c0910fcd93b409ba56e45fc202cf"
|
||||
oni-fontkit@^0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/oni-fontkit/-/oni-fontkit-0.0.5.tgz#06b9400d549de3395bb7d88266b4703c09ba407f"
|
||||
dependencies:
|
||||
babel-runtime "^6.11.6"
|
||||
brotli "^1.2.0"
|
||||
|
@ -8079,6 +8108,12 @@ path-to-regexp@0.1.7:
|
|||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
|
||||
path-to-regexp@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
|
||||
dependencies:
|
||||
isarray "0.0.1"
|
||||
|
||||
path-type@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||
|
@ -8609,6 +8644,13 @@ pump@^2.0.0, pump@^2.0.1:
|
|||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
pump@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
|
||||
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"
|
||||
|
@ -9445,13 +9487,9 @@ safe-regex@^1.1.0:
|
|||
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"
|
||||
|
||||
samsam@~1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.3.tgz#9f5087419b4d091f232571e7fa52e90b0f552621"
|
||||
samsam@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
|
||||
|
||||
sane@^2.0.0:
|
||||
version "2.4.1"
|
||||
|
@ -9632,13 +9670,13 @@ shebang-regex@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||
|
||||
shell-env@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/shell-env/-/shell-env-0.3.0.tgz#2250339022989165bda4eb7bf383afeaaa92dc34"
|
||||
shell-env@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/shell-env/-/shell-env-2.1.0.tgz#11c472dd59c9ebe3fdeca115bd98ce0c9cbbcc7d"
|
||||
dependencies:
|
||||
default-shell "^1.0.0"
|
||||
execa "^0.5.0"
|
||||
strip-ansi "^3.0.0"
|
||||
default-shell "^1.0.1"
|
||||
execa "^1.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
shell-quote@^1.6.1:
|
||||
version "1.6.1"
|
||||
|
@ -9691,14 +9729,17 @@ single-line-log@^1.1.2:
|
|||
dependencies:
|
||||
string-width "^1.0.1"
|
||||
|
||||
sinon@1.17.6:
|
||||
version "1.17.6"
|
||||
resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.17.6.tgz#a43116db59577c8296356afee13fafc2332e58e1"
|
||||
sinon@5.0.5:
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/sinon/-/sinon-5.0.5.tgz#d89609395962322ac2fee7f9286abaa3b8fe6957"
|
||||
dependencies:
|
||||
formatio "1.1.1"
|
||||
lolex "1.3.2"
|
||||
samsam "1.1.2"
|
||||
util ">=0.10.3 <1"
|
||||
"@sinonjs/formatio" "^2.0.0"
|
||||
diff "^3.1.0"
|
||||
lodash.get "^4.4.2"
|
||||
lolex "^2.2.0"
|
||||
nise "^1.2.0"
|
||||
supports-color "^5.1.0"
|
||||
type-detect "^4.0.5"
|
||||
|
||||
sisteransi@^0.1.1:
|
||||
version "0.1.1"
|
||||
|
@ -10379,6 +10420,10 @@ test-exclude@^4.2.1:
|
|||
read-pkg-up "^1.0.1"
|
||||
require-main-filename "^1.0.1"
|
||||
|
||||
text-encoding@^0.6.4:
|
||||
version "0.6.4"
|
||||
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||
|
@ -10547,9 +10592,9 @@ tslib@^1.8.0, tslib@^1.8.1:
|
|||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
|
||||
|
||||
tslint@5.9.1:
|
||||
version "5.9.1"
|
||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae"
|
||||
tslint@^5.11.0:
|
||||
version "5.11.0"
|
||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed"
|
||||
dependencies:
|
||||
babel-code-frame "^6.22.0"
|
||||
builtin-modules "^1.1.1"
|
||||
|
@ -10562,11 +10607,11 @@ tslint@5.9.1:
|
|||
resolve "^1.3.2"
|
||||
semver "^5.3.0"
|
||||
tslib "^1.8.0"
|
||||
tsutils "^2.12.1"
|
||||
tsutils "^2.27.2"
|
||||
|
||||
tsutils@^2.12.1:
|
||||
version "2.19.1"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.19.1.tgz#76d7ebdea9d7a7bf4a05f50ead3701b0168708d7"
|
||||
tsutils@^2.27.2:
|
||||
version "2.29.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
|
||||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
|
@ -10590,6 +10635,10 @@ type-check@~0.3.2:
|
|||
dependencies:
|
||||
prelude-ls "~1.1.2"
|
||||
|
||||
type-detect@^4.0.5:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
|
||||
|
||||
type-is@~1.6.15:
|
||||
version "1.6.15"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
|
||||
|
@ -10614,9 +10663,9 @@ typescript-plugin-styled-components@^0.0.6:
|
|||
dependencies:
|
||||
ts-is-kind "^1.0.0"
|
||||
|
||||
typescript@^2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624"
|
||||
typescript@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.1.tgz#3362ba9dd1e482ebb2355b02dfe8bcd19a2c7c96"
|
||||
|
||||
ua-parser-js@^0.7.9:
|
||||
version "0.7.17"
|
||||
|
@ -10851,7 +10900,7 @@ util.promisify@^1.0.0:
|
|||
define-properties "^1.1.2"
|
||||
object.getownpropertydescriptors "^2.0.3"
|
||||
|
||||
util@0.10.3, "util@>=0.10.3 <1", util@^0.10.3:
|
||||
util@0.10.3, util@^0.10.3:
|
||||
version "0.10.3"
|
||||
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
|
||||
dependencies:
|
||||
|
@ -10989,17 +11038,35 @@ vscode-languageserver-protocol@3.5.0, vscode-languageserver-protocol@^3.5.0:
|
|||
vscode-jsonrpc "^3.5.0"
|
||||
vscode-languageserver-types "^3.5.0"
|
||||
|
||||
vscode-languageserver-types@3.5.0, vscode-languageserver-types@^3.5.0:
|
||||
vscode-languageserver-protocol@3.5.1:
|
||||
version "3.5.1"
|
||||
resolved "http://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.1.tgz#5144a3a9eeccbd83fe2745bd4ed75fad6cc45f0d"
|
||||
dependencies:
|
||||
vscode-jsonrpc "3.5.0"
|
||||
vscode-languageserver-types "3.5.0"
|
||||
|
||||
vscode-languageserver-types@3.13.0, vscode-languageserver-types@^3.5.0:
|
||||
version "3.13.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4"
|
||||
|
||||
vscode-languageserver-types@3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374"
|
||||
|
||||
vscode-languageserver@3.5.0, vscode-languageserver@^3.5.0:
|
||||
vscode-languageserver@3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-3.5.0.tgz#d28099bc6ddda8c1dd16b707e454e1b1ddae0dba"
|
||||
dependencies:
|
||||
vscode-languageserver-protocol "^3.5.0"
|
||||
vscode-uri "^1.0.1"
|
||||
|
||||
vscode-languageserver@^3.5.0:
|
||||
version "3.5.1"
|
||||
resolved "http://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.1.tgz#e0044b7df4d2447ce12632dfc98f1ab0afacbdff"
|
||||
dependencies:
|
||||
vscode-languageserver-protocol "3.5.1"
|
||||
vscode-uri "^1.0.1"
|
||||
|
||||
vscode-nls@^2.0.1, vscode-nls@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da"
|
||||
|
|
Loading…
Reference in New Issue