Skip to content

Commit

Permalink
Merge v0.4.1 'dev' into 'master' (#30)
Browse files Browse the repository at this point in the history
* Better support for partial completions (#29)

* Bugfix for Issue #28

* Updated CHANGELOG for v0.4.1
  • Loading branch information
ethall authored Sep 23, 2018
1 parent d642867 commit 01ecb2a
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 54 deletions.
20 changes: 12 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [v0.4.1] - 2018-09-23
### Changed
- How completions and signatures are generated behind the scenes, resulting in a lower memory footprint.
- Completions and signatures are now dynamically generated behind the scenes, resulting in a lower memory footprint. *(#19)*
### Fixed
- Fixed document unregistration in `tspManager` if it lacked a shebang.
- Corrected the completion label for `status.condition`.
- Removed unnecessary asterisk escapes.
- Added missing `smu.interlock` and `trigger.model` 2450 commands.
- Fixed document unregistration in `tspManager` if it lacked a shebang. *(#19)*
- Corrected the completion label for `status.condition`. *(#19)*
- Added missing `smu.interlock` and `trigger.model` 2450 commands. *(#20)*
- Removed unnecessary asterisk escapes. *(#21)*
- Gutted and replaced the signature detection system. The displayed parameter help should now more accurately reflect the current function call. *(#26)*
- Fixed partial completions not being displayed when the Trigger Suggest keyboard shortcut was used. *(#28)*

## 0.4.0 - 2018-09-07
### Added
- Model 2450 support.
- Lua 5.0.3 support.

- Lua 5.0.3 support. *(#10)*
### Removed
- Models 2460, 2461, 2461-SYS, and 6500 from the release package.

[Unreleased]: https://github.com/tektronixofficial/vscode-tsplang/compare/v0.4.0...HEAD
[Unreleased]: https://github.com/tektronixofficial/vscode-tsplang/compare/v0.4.1...HEAD
[v0.4.1]: https://github.com/tektronixofficial/vscode-tsplang/compare/v0.4.0...v0.4.1
63 changes: 63 additions & 0 deletions server/src/completionProcessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2018 Tektronix Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'

import { CompletionItem } from 'vscode-languageserver'

export function isPartialMatch(content: string, completion: CompletionItem): boolean {
// If content is an empty string, then everything is a partial match
if (content.localeCompare('') === 0) {
return true
}

const completionData: Array<string> = (completion.data === undefined) ? [] : completion.data

let names: Array<string> = content.split('.')

// Get the (possibly partial or empty) name requesting suggestions.
// Array.pop returns undefined if the array is empty but String.split always returns an
// array with at least 1 item, so disregard the undefined type.
const lastName = names.pop() as string

// Reverse the remaining names so we can more easily match against CompletionItem.data.
names = names.reverse()

// If the given completion's namespace length does not match our content's namespace length
if (completionData.length !== names.length) {
return false
}

// If the given completion has an identical namespace
if (completionData.join('.').localeCompare(names.join('.')) === 0) {
// If the last name is an empty string, then everything is a partial match
if (lastName.localeCompare('') === 0) {
return true
}

const labelRegexp = new RegExp('^' + lastName + '.*$')

const matches = completion.label.match(labelRegexp)

if (matches === null) {
return false
}
else {
return true
}
}

return false
}
49 changes: 5 additions & 44 deletions server/src/contentHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@

import { CompletionItem, Position, SignatureHelp, SignatureInformation, TextDocuments } from 'vscode-languageserver'

import { getActiveParameter, getOffsetOfUnmatched } from './contentProcessor'
import { isPartialMatch } from './completionProcessor'
import { resolveCompletionNamespace } from './instrument/provider'
import { parentheses } from './lua/pair'
import { getActiveParameter, getOffsetOfUnmatched } from './signatureProcessor'
import { TspItem } from './tspManager'

export class ContentHandler {
Expand Down Expand Up @@ -89,7 +90,7 @@ export class ContentHandler {

const results: Array<CompletionItem> = new Array()

let firstMatch = reverseMatches.shift()
const firstMatch = reverseMatches.shift()

// Show root namespace completions if we did not match against a namespace
if (firstMatch === undefined || firstMatch === '') {
Expand All @@ -103,52 +104,12 @@ export class ContentHandler {
return results
}

let endingQualifier = false

// Remove any trailing namespace qualifiers (".").
// Since the string is reversed, this is index 0.
if (firstMatch.indexOf('.') === 0) {
firstMatch = firstMatch.slice(1)
endingQualifier = true

// Return if we just deleted the entire string
if (firstMatch.length === 0) {
return
}
}

// Un-reverse the string and remove any table indexers
const unreversed = this.reverse(firstMatch.replace(this.tableIndexRegexp, ''))
// Split the unreversed string on namespace qualifiers and reverse the resulting array
const reverseNamespaceArray: Array<string> = unreversed.split('.').reverse()

for (const completion of tspItem.commandSet.completions) {
// Use the "data" property if it exists...
if (completion.data !== undefined) {
if (completion.data.join('.') === reverseNamespaceArray.join('.')) {
results.push(completion)
}
}
// ...otherwise this completion should be treated as a root namespace.
else {
// Do not include a root namespace in our results if the last character
// of the user's current namespace is a namespace qualifier.
// Suggest the foo module on a "foo" match but not on a "foo." match.
if (endingQualifier) {
continue
}

// Partial match against the "label" property
const partialMatches = completion.label.match(reverseNamespaceArray.join('.'))

if (partialMatches === null) {
continue
}

const partial = partialMatches.shift()
if (partial !== undefined && partial.length !== 0) {
results.push(completion)
}
if (isPartialMatch(unreversed, completion)) {
results.push(completion)
}
}

Expand Down
File renamed without changes.
114 changes: 114 additions & 0 deletions test/server/src/completionProcessor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright 2018 Tektronix Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// tslint:disable:no-implicit-dependencies no-magic-numbers prefer-function-over-method
import { assert } from 'chai'
import { suite, test } from 'mocha-typescript'
import { CompletionItem } from 'vscode-languageclient'

import { isPartialMatch } from '../../../server/src/completionProcessor'

function toString(completion: CompletionItem): string {
let result = '{label: "' + completion.label + '"'

if (completion.data !== undefined) {
result += ', data: ['
completion.data.forEach((item: string) => {
result += '"' + item + '", '
})
// Remove the trailing ", "
result = result.slice(0, result.length - 2)
result += ']'
}

return result + '}'
}

@suite class CompletionProcessorTest {
@test('isPartialMatch')
isPartialMatchTest(): void {
let testString = ''
let testCompletion: CompletionItem = {
label: 'a'
}
assert(
isPartialMatch(testString, testCompletion),
'"' + testString + '" did not partially match "' + toString(testCompletion) + '"'
)

testCompletion = {
data: ['b'],
label: 'a'
}
assert(
isPartialMatch(testString, testCompletion),
'"' + testString + '" did not partially match "' + toString(testCompletion) + '"'
)

testString = 'a.'
testCompletion = {
label: 'a'
}
assert(
! isPartialMatch(testString, testCompletion),
'"' + testString + '" partially matched "' + toString(testCompletion) + '"'
)

testCompletion = {
data: ['a'],
label: 'b'
}
assert(
isPartialMatch(testString, testCompletion),
'"' + testString + '" did not partially match "' + toString(testCompletion) + '"'
)

testString = 'a.p'
testCompletion = {
label: 'a'
}
assert(
! isPartialMatch(testString, testCompletion),
'"' + testString + '" partially matched "' + toString(testCompletion) + '"'
)

testCompletion = {
data: ['a'],
label: 'b'
}
assert(
! isPartialMatch(testString, testCompletion),
'"' + testString + '" partially matched "' + toString(testCompletion) + '"'
)

testCompletion = {
data: ['b'],
label: 'partial'
}
assert(
! isPartialMatch(testString, testCompletion),
'"' + testString + '" partially matched "' + toString(testCompletion) + '"'
)

testCompletion = {
data: ['a'],
label: 'partial'
}
assert(
isPartialMatch(testString, testCompletion),
'"' + testString + '" did not partially match "' + toString(testCompletion) + '"'
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
import { assert } from 'chai'
import { suite, test } from 'mocha-typescript'

import { getActiveParameter, getOffsetOfUnmatched } from '../../../server/src/contentProcessor'
import { parentheses } from '../../../server/src/lua/pair'
import { getActiveParameter, getOffsetOfUnmatched } from '../../../server/src/signatureProcessor'

@suite class ContentProcessorTest {
@suite class SignatureProcessorTest {
@test('getActiveParameter')
getActiveParameterTest(): void {
let testString = ''
Expand Down

0 comments on commit 01ecb2a

Please sign in to comment.