Skip to content

Commit

Permalink
✨ Finish all completions in NbtTagArgumentParser
Browse files Browse the repository at this point in the history
Resolve #28
  • Loading branch information
SPGoding committed Oct 28, 2019
1 parent 10f0122 commit 15d6119
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 45 deletions.
6 changes: 3 additions & 3 deletions src/parsers/LiteralArgumentParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ export default class LiteralArgumentParser extends ArgumentParser<string> {
if (literals.length === 0) {
throw new Error('expected ‘literals.length’ to be more than 0')
}
this.literals = literals.sort()
this.literals = literals
}

parse(reader: StringReader): ArgumentParserResult<string> {
parse(reader: StringReader, cursor: number = -1): ArgumentParserResult<string> {
const ans: ArgumentParserResult<string> = {
data: '',
errors: [],
cache: {},
completions: []
}
//#region Get completions.
if (!reader.canRead()) {
if (reader.cursor === cursor) {
ans.completions = this.literals.map(v => ({ label: v }))
}
//#endregion
Expand Down
24 changes: 21 additions & 3 deletions src/parsers/NbtTagArgumentParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { nbtDocs } from 'mc-nbt-paths'
import NbtSchemaWalker, { NbtCompoundSchemaNode } from '../utils/NbtSchemaWalker'
import { checkNamingConvention } from '../types/NamingConventionConfig'
import BigNumber from 'bignumber.js'
import { arrayToMessage } from '../utils/utils'
import { arrayToMessage, quoteString, escapeString } from '../utils/utils'

export default class NbtTagArgumentParser extends ArgumentParser<NbtTag> {
/**
Expand Down Expand Up @@ -177,6 +177,19 @@ export default class NbtTagArgumentParser extends ArgumentParser<NbtTag> {
if (this.cursor === start) {
ans.completions.push({ label: `[${walker.read().type.toUpperCase()[0]};]` })
}
} else if (walker.read().type === 'string') {
const clonedReader = reader.clone()
ans = this.parsePrimitiveTag(reader, walker)
if (this.cursor === start) {
ans.completions.push(
...walker
.getCompletions(clonedReader, this.cursor, this.config, this.cache)
.map(v => ({
...v,
label: quoteString(v.label, this.config.lint.quoteType, this.config.lint.quoteSnbtStringValues)
}))
)
}
} else {
ans = this.parsePrimitiveTag(reader, walker)
}
Expand Down Expand Up @@ -359,7 +372,7 @@ export default class NbtTagArgumentParser extends ArgumentParser<NbtTag> {
}
}

private parsePrimitiveArray(reader: StringReader, walker?: NbtSchemaWalker,
private parsePrimitiveArray(reader: StringReader, _walker?: NbtSchemaWalker,
specifiedType: 'byte_array' | 'int_array' | 'long_array' | null = null):
ArgumentParserResult<NbtByteArrayTag | NbtIntArrayTag | NbtLongArrayTag> {
const ans: ArgumentParserResult<NbtByteArrayTag | NbtIntArrayTag | NbtLongArrayTag> = {
Expand Down Expand Up @@ -500,13 +513,18 @@ export default class NbtTagArgumentParser extends ArgumentParser<NbtTag> {
private parsePrimitiveTag(reader: StringReader, walker?: NbtSchemaWalker): ArgumentParserResult<NbtTag> {
if (StringReader.isQuote(reader.peek())) {
// Parse as a quoted string.
const quote = reader.peek()
try {
const clonedReader = reader.clone().skip()
const value = reader.readQuotedString()
return {
data: getNbtStringTag(value),
errors: [],
cache: {},
completions: []
completions: walker ?
walker.getCompletions(clonedReader, this.cursor, this.config, this.cache)
.map(v => ({ ...v, label: escapeString(v.label, quote as any) })) :
[]
}
} catch (p) {
return {
Expand Down
18 changes: 9 additions & 9 deletions src/test/parsers/LiteralArgumentParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ describe('LiteralArgumentParser Tests', () => {
it('Should return correctly for multi literals', () => {
const parser = new LiteralArgumentParser('foo', 'bar')
const actual = parser.toHint()
assert.strictEqual(actual, '(bar|foo)')
assert.strictEqual(actual, '(foo|bar)')
})
})
describe('getExamples() Tests', () => {
it('Should return examples', () => {
const parser = new LiteralArgumentParser('foo', 'bar')
const actual = parser.getExamples()
assert.deepStrictEqual(actual, ['bar', 'foo'])
assert.deepStrictEqual(actual, ['foo', 'bar'])
})
})
describe('parse() Tests', () => {
Expand All @@ -48,13 +48,13 @@ describe('LiteralArgumentParser Tests', () => {
const actual = parser.parse(new StringReader('actual'))
assert(actual.data === 'actual')
})
it('Should return completions for empty input', () => {
it('Should return completions', () => {
const parser = new LiteralArgumentParser('foo', 'bar')
const actual = parser.parse(new StringReader(''))
const actual = parser.parse(new StringReader(''), 0)
assert.deepStrictEqual(actual.completions,
[
{ label: 'bar' },
{ label: 'foo' }
{ label: 'foo' },
{ label: 'bar' }
]
)
})
Expand All @@ -64,7 +64,7 @@ describe('LiteralArgumentParser Tests', () => {
const pe = (<ParsingError[]>errors)[0]
assert(pe.range.start === 0)
assert(pe.range.end === 1)
assert(pe.message.match(/expected one of ‘bar’ and ‘foo’ but got nothing/))
assert(pe.message.match(/expected one of ‘foo’ and ‘bar’ but got nothing/))
assert(pe.tolerable === false)
})
it('Should return errors when partial matching', () => {
Expand All @@ -73,7 +73,7 @@ describe('LiteralArgumentParser Tests', () => {
const pe = (<ParsingError[]>errors)[0]
assert(pe.range.start === 0)
assert(pe.range.end === 1)
assert(pe.message.match(/expected one of ‘bar’ and ‘foo’ but got ‘F’/))
assert(pe.message.match(/expected one of ‘foo’ and ‘bar’ but got ‘F’/))
assert(pe.tolerable === true)
})
it('Should return untolerable error when nothing matches', () => {
Expand All @@ -82,7 +82,7 @@ describe('LiteralArgumentParser Tests', () => {
const pe = (<ParsingError[]>errors)[0]
assert(pe.range.start === 0)
assert(pe.range.end === 3)
assert(pe.message.match(/expected one of ‘bar’ and ‘foo’ but got ‘spg’/))
assert(pe.message.match(/expected one of ‘foo’ and ‘bar’ but got ‘spg’/))
assert(pe.tolerable === false)
})
})
Expand Down
89 changes: 60 additions & 29 deletions src/test/parsers/NbtTagArgumentParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -584,30 +584,10 @@ describe('NbtTagArgumentParser Tests', () => {
byteArray: { type: 'byte_array' },
intArray: { type: 'int_array' },
longArray: { type: 'long_array' },
primitive: { type: 'string' },
raw: {
type: 'no-nbt',
suggestions: ['foo']
},
detailed: {
type: 'no-nbt',
suggestions: [{ value: 'bar', description: 'The Bar' }]
},
argumentParser: {
type: 'no-nbt',
suggestions: [{ parser: 'Literal', params: ['baz', 'qux'] }]
},
lineParser: {
type: 'no-nbt',
suggestions: [{
parser: '#', params: [
true,
'commands',
{
commands: { execute: { parser: new LiteralArgumentParser('foo'), executable: true } }
}
]
}]
primitive: { type: 'byte' },
string: {
type: 'string',
suggestions: [{ parser: 'Literal', params: ['foo', '"bar"'] }]
}
}
},
Expand Down Expand Up @@ -811,7 +791,7 @@ describe('NbtTagArgumentParser Tests', () => {
assert.deepStrictEqual(cache, {})
assert.deepStrictEqual(completions, [])
})
it('Should return empty completions when the schema is a primitive type', () => {
it('Should return empty completions when the schema is a non-string primitive type', () => {
const parser = new NbtTagArgumentParser('compound', 'blocks', 'spgoding:suggestions_test', schemas)
const reader = new StringReader('{ primitive: }')
const { data, errors, cache, completions } = parser.parse(reader, 13)
Expand All @@ -820,10 +800,10 @@ describe('NbtTagArgumentParser Tests', () => {
primitive: getNbtStringTag('')
}
))
assert.deepStrictEqual(errors, [new ParsingError(
{ start: 13, end: 14 },
'expected a tag but got nothing'
)])
assert.deepStrictEqual(errors, [
new ParsingError({ start: 13, end: 14 }, 'expected a tag but got nothing'),
new ParsingError({ start: 13, end: 13 }, 'expected a byte tag instead of a string tag', true, DiagnosticSeverity.Warning),
])
assert.deepStrictEqual(cache, {})
assert.deepStrictEqual(completions, [])
})
Expand Down Expand Up @@ -983,6 +963,22 @@ describe('NbtTagArgumentParser Tests', () => {
assert.deepStrictEqual(cache, {})
assert.deepStrictEqual(completions, [])
})
it('Should return empty completions when the cursor is not at the point for string tag quotes', () => {
const parser = new NbtTagArgumentParser('compound', 'blocks', 'spgoding:suggestions_test', schemas)
const reader = new StringReader('{ string: }')
const { data, errors, cache, completions } = parser.parse(reader)
assert.deepEqual(data, getNbtCompoundTag(
{
string: getNbtStringTag('')
}
))
assert.deepStrictEqual(errors, [new ParsingError(
{ start: 10, end: 11 },
'expected a tag but got nothing'
)])
assert.deepStrictEqual(cache, {})
assert.deepStrictEqual(completions, [])
})
it('Should return completions for compound tag keys', () => {
const parser = new NbtTagArgumentParser('compound', 'blocks', 'spgoding:suggestions_test', schemas)
const reader = new StringReader('{ compound: {} }')
Expand Down Expand Up @@ -1013,6 +1009,41 @@ describe('NbtTagArgumentParser Tests', () => {
assert.deepStrictEqual(cache, {})
assert.deepStrictEqual(completions, [])
})
it('Should return completions for empty string tags', () => {
const parser = new NbtTagArgumentParser('compound', 'blocks', 'spgoding:suggestions_test', schemas)
const reader = new StringReader('{ string: }')
const { data, errors, cache, completions } = parser.parse(reader, 10)
assert.deepEqual(data, getNbtCompoundTag(
{
string: getNbtStringTag('')
}
))
assert.deepStrictEqual(errors, [new ParsingError(
{ start: 10, end: 11 },
'expected a tag but got nothing'
)])
assert.deepStrictEqual(cache, {})
assert.deepStrictEqual(completions, [
{ label: '"foo"' },
{ label: `'"bar"'` }
])
})
it('Should return completions inside quoted string tags', () => {
const parser = new NbtTagArgumentParser('compound', 'blocks', 'spgoding:suggestions_test', schemas)
const reader = new StringReader('{ string: "" }')
const { data, errors, cache, completions } = parser.parse(reader, 11)
assert.deepEqual(data, getNbtCompoundTag(
{
string: getNbtStringTag('')
}
))
assert.deepStrictEqual(errors, [])
assert.deepStrictEqual(cache, {})
assert.deepStrictEqual(completions, [
{ label: 'foo' },
{ label: '\\"bar\\"' }
])
})
})
})
})
2 changes: 1 addition & 1 deletion src/utils/StringReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ export default class StringReader {
return /^[0-9a-zA-Z\_\-\.\+]+$/.test(string)
}

static isQuote(c: string) {
static isQuote(c: string): c is '"' | "'" {
return c === '"' || c === "'"
}
}

0 comments on commit 15d6119

Please sign in to comment.