Skip to content

Commit 54d3462

Browse files
authored
Merge pull request #10 from codefori/feature/editors/record_format_keywords
2 parents 6455de6 + 5245adc commit 54d3462

File tree

4 files changed

+139
-34
lines changed

4 files changed

+139
-34
lines changed

src/tests/dspf.test.ts

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect, describe, it } from "vitest";
22
import { DdsLineRange, DisplayFile, FieldInfo } from "../ui/dspf";
3+
import exp from "constants";
34

45
describe('DisplayFile tests', () => {
56

@@ -28,15 +29,15 @@ describe('DisplayFile tests', () => {
2829
let dds = new DisplayFile();
2930
dds.parse(dspf1);
3031

31-
expect(dds.getRangeForFormat(`DONOTEXIST`)).toBeUndefined();
32+
expect(dds.getHeaderRangeForFormat(`DONOTEXIST`)).toBeUndefined();
3233

3334
let range: DdsLineRange | undefined;
3435

35-
range = dds.getRangeForFormat(`FMT1`);
36+
range = dds.getHeaderRangeForFormat(`FMT1`);
3637
expect(range?.start).toBe(3);
3738
expect(range?.end).toBe(9);
3839

39-
range = dds.getRangeForFormat(`HEAD`);
40+
range = dds.getHeaderRangeForFormat(`HEAD`);
4041
expect(range?.start).toBe(1);
4142
expect(range?.end).toBe(3);
4243
});
@@ -56,13 +57,48 @@ describe('DisplayFile tests', () => {
5657
range = dds.getRangeForField(`FORM1`, `FLD0102`);
5758
expect(range?.start).toBe(17);
5859
expect(range?.end).toBe(17);
59-
6060
});
6161

62-
it('getLinesForField', () => {
63-
62+
it('generates the same as what is provided', () => {
6463
let dds = new DisplayFile();
64+
dds.parse(dspf1);
65+
66+
const form1 = dds.formats.find(f => f.name === `FORM1`);
67+
expect(form1).toBeDefined();
68+
69+
const FLD0101 = form1?.fields.find(f => f.name === `FLD0101`);
70+
expect(FLD0101).toBeDefined();
71+
expect(FLD0101?.keywords.length).toBe(2);
72+
73+
const DSPATR = FLD0101?.keywords.find(k => k.name === `DSPATR`);
74+
expect(DSPATR).toBeDefined();
75+
expect(DSPATR?.value).toBe(`PR`);
76+
expect(DSPATR?.conditions.length).toBe(1);
77+
78+
const cond = DSPATR?.conditions[0];
79+
expect(cond).toBeDefined();
80+
expect(cond?.indicator).toBe(20);
81+
expect(cond?.negate).toBeFalsy();
6582

83+
const generatedKeywordLines = DisplayFile.getLinesForKeyword(DSPATR!);
84+
expect(generatedKeywordLines.length).toBe(1);
85+
expect(generatedKeywordLines[0]).toBe(dspf1[15].trimEnd());
86+
87+
const generateFieldLines = DisplayFile.getLinesForField(FLD0101!);
88+
expect(generateFieldLines.length).toBe(3);
89+
90+
expect(generateFieldLines[0]).toBe(dspf1[14].trimEnd());
91+
expect(generateFieldLines[1]).toBe(dspf1[15].trimEnd());
92+
expect(generateFieldLines[2]).toBe(dspf1[16].trimEnd());
93+
94+
const generatedRecordFormatLines = DisplayFile.getHeaderLinesForFormat(form1!.name, form1!.keywords);
95+
expect(generatedRecordFormatLines.length).toBe(2);
96+
expect(generatedRecordFormatLines[0]).toBe(dspf1[12].trimEnd());
97+
expect(generatedRecordFormatLines[1]).toBe(dspf1[13].trimEnd());
98+
99+
});
100+
101+
it('getLinesForField', () => {
66102
let field = new FieldInfo(0);
67103
field.displayType = `const`;
68104
field.value = `Some text`;
@@ -92,7 +128,6 @@ describe('DisplayFile tests', () => {
92128
expect(lines[0]).toBe(` A 4 10'Some text'`);
93129
expect(lines[1]).toBe(` A COLOR(BLU)`);
94130
expect(lines[2]).toBe(` A DSPATR(PR)`);
95-
96131
});
97132

98133
it('No duplicate RecordInfo', () => {

src/ui/dspf.ts

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,7 @@ export class DisplayFile {
230230
static parseConditionals(conditionColumns: string): Conditional[] {
231231
if (conditionColumns.trim() === "") {return [];}
232232

233-
/** @type {Conditional[]} */
234-
let conditionals = [];
233+
let conditionals: Conditional[] = [];
235234

236235
//TODO: something with condition
237236
//const condition = conditionColumns.substring(0, 1); //A (and) or O (or)
@@ -351,6 +350,37 @@ export class DisplayFile {
351350
return result;
352351
}
353352

353+
private static conditionalGroups(conditions: Conditional[]) {
354+
return conditions.reduce((acc, curr, index) => {
355+
if (index % 3 === 0) {
356+
acc.push([curr]);
357+
} else {
358+
acc[acc.length - 1].push(curr);
359+
}
360+
return acc;
361+
}, [] as Conditional[][]);
362+
}
363+
364+
public static getLinesForKeyword(keyword: Keyword): string[] {
365+
const lines: string[] = [];
366+
367+
// Convert array into groups of three
368+
const condition = this.conditionalGroups(keyword.conditions);
369+
370+
const firstConditions = condition[0] || [];
371+
const conditionStrings = firstConditions.map(c => `${c.negate ? 'N' : ' '}${c.indicator}`).join('').padEnd(9);
372+
373+
lines.push(` A ${conditionStrings} ${keyword.name}${keyword.value ? `(${keyword.value})` : ``}`);
374+
375+
for (let g = 1; g < condition.length; g++) {
376+
const group = condition[g];
377+
const conditionStrings = group.map(c => `${c.negate ? 'N' : ' '}${c.indicator}`).join('');
378+
lines.push(` A ${conditionStrings}`);
379+
}
380+
381+
return lines;
382+
}
383+
354384
public static getLinesForField(field: FieldInfo): string[] {
355385
const newLines: string[] = [];
356386

@@ -366,25 +396,27 @@ export class DisplayFile {
366396
const y = String(field.position.y).padStart(3, ` `);
367397
const displayType = FIELD_TYPE[field.displayType!];
368398

399+
// Convert array into groups of three
400+
const condition = this.conditionalGroups(field.conditions);
401+
const firstConditions = condition[0] || [];
402+
const conditionStrings = firstConditions.map(c => `${c.negate ? 'N' : ' '}${c.indicator}`).join('').padEnd(9);
403+
369404
if (field.displayType === `const`) {
370405
const value = field.value;
371406
newLines.push(
372-
` A ${y}${x}'${value}'`,
407+
` A ${conditionStrings} ${y}${x}'${value}'`,
373408
);
374409
} else if (displayType && field.name) {
375410
const definitionType = field.type;
376411
const length = String(field.length).padStart(5);
377-
const decimals = String(field.decimals).padStart(2);
412+
const decimals = (field.type !== `A` ? String(field.decimals) : ``).padStart(2);
378413
newLines.push(
379-
` A ${field.name.padEnd(10)} ${length}${definitionType}${decimals}${displayType}${y}${x}`,
414+
` A ${conditionStrings} ${field.name.padEnd(10)} ${length}${definitionType}${decimals}${displayType}${y}${x}`,
380415
);
381416
}
382417

383418
for (const keyword of field.keywords) {
384-
// TODO: support conditions
385-
newLines.push(
386-
` A ${keyword.name}${keyword.value ? `(${keyword.value})` : ``}`,
387-
);
419+
newLines.push(...DisplayFile.getLinesForKeyword(keyword));
388420
}
389421

390422
return newLines;
@@ -437,24 +469,22 @@ export class DisplayFile {
437469
}
438470

439471
// TODO: test cases
440-
static getLinesForFormat(recordFormat: RecordInfo): string[] {
472+
static getHeaderLinesForFormat(recordFormat: string, keywords: Keyword[]): string[] {
441473
const lines: string[] = [];
442474

443-
if (recordFormat.name !== GLOBAL_RECORD_NAME) {
444-
lines.push(` A R ${recordFormat.name}`);
475+
if (recordFormat) {
476+
lines.push(` A R ${recordFormat}`);
445477
}
446478

447-
for (const keyword of recordFormat.keywords) {
479+
for (const keyword of keywords) {
448480
// TODO: support conditions
449-
lines.push(
450-
` A ${keyword.name}${keyword.value ? `(${keyword.value})` : ``}`,
451-
);
481+
lines.push(...DisplayFile.getLinesForKeyword(keyword));
452482
}
453483

454484
return lines;
455485
}
456486

457-
public getRangeForFormat(recordFormat: string): DdsLineRange|undefined {
487+
public getHeaderRangeForFormat(recordFormat: string): DdsLineRange|undefined {
458488
let range: DdsLineRange|undefined = undefined;
459489
const currentFormatI = this.formats.findIndex(format => format.name === recordFormat);
460490
if (currentFormatI > 0) {
@@ -474,9 +504,9 @@ export class DisplayFile {
474504
}
475505

476506
// TODO: test cases
477-
public updateFormat(originalFormatName: string, newRecordFormat: RecordInfo): DdsUpdate|undefined {
478-
const newLines = DisplayFile.getLinesForFormat(newRecordFormat);
479-
let range = this.getRangeForFormat(originalFormatName);
507+
public updateFormatHeader(originalFormatName: string, keywords: Keyword[]): DdsUpdate|undefined {
508+
const newLines = DisplayFile.getHeaderLinesForFormat(originalFormatName, keywords);
509+
let range = this.getHeaderRangeForFormat(originalFormatName);
480510

481511
if (range) {
482512
range = {

src/ui/index.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { readFile, readFileSync } from "fs";
2-
import { WebviewViewProvider, WebviewView, Uri, CancellationToken, WebviewViewResolveContext, Webview, DiagnosticSeverity, window, WebviewPanel, ViewColumn, ExtensionContext, workspace, TextDocument, TextEdit, Range, WorkspaceEdit, Position } from "vscode";
3-
import { basename } from "path";
4-
import { DisplayFile, FieldInfo } from "./dspf";
1+
import { readFileSync } from "fs";
2+
import { Uri, Webview, window, WebviewPanel, ViewColumn, ExtensionContext, workspace, TextDocument, Range, WorkspaceEdit, Position } from "vscode";
3+
import { DisplayFile, FieldInfo, Keyword, RecordInfo } from "./dspf";
54

65

76
export class RendererWebview {
@@ -126,7 +125,32 @@ export class RendererWebview {
126125
);
127126

128127
await workspace.applyEdit(workspaceEdit);
129-
this.load(false);
128+
this.load(false); //Field is updated on the client
129+
}
130+
}
131+
}
132+
break;
133+
134+
case `updateFormat`:
135+
// This does not update any of the fields in the record format, only the format header
136+
recordFormat = message.recordFormat;
137+
const newKeywords: Keyword[] = message.newKeywords;
138+
139+
if (typeof recordFormat === `string` && Array.isArray(newKeywords)) {
140+
const formatUpdate = this.dds?.updateFormatHeader(recordFormat, newKeywords);
141+
142+
if (formatUpdate) {
143+
if (formatUpdate.range && this.document) {
144+
const workspaceEdit = new WorkspaceEdit();
145+
workspaceEdit.replace(
146+
this.document.uri,
147+
new Range(formatUpdate.range.start, 0, formatUpdate.range.end, 1000),
148+
formatUpdate.newLines.join('\n'), // TOOD: use the correct EOL?
149+
{label: `Update DDS Format`, needsConfirmation: false}
150+
);
151+
152+
await workspace.applyEdit(workspaceEdit);
153+
this.load(true);
130154
}
131155
}
132156
}

webui/main.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ const timeFormats = {
4444
'*JIS': 'hh:mm:ss',
4545
};
4646

47+
const GLOBAL_RECORD_FORMAT = `_GLOBAL`;
48+
4749
const vscode = acquireVsCodeApi();
4850

4951
const pxwPerChar = 8.45;
@@ -92,7 +94,7 @@ function loadDDS(newDoc, type, withRerender = true) {
9294
activeDocumentType = type;
9395

9496
if (withRerender) {
95-
const validFormats = activeDocument.formats.filter(format => format.name !== `GLOBAL`);
97+
const validFormats = activeDocument.formats.filter(format => format.name !== GLOBAL_RECORD_FORMAT);
9698

9799
setTabs(validFormats.map(format => format.name), lastSelectedFormat);
98100

@@ -777,7 +779,9 @@ function updateRecordFormatSidebar(recordInfo, globalInfo) {
777779

778780
sections.push({
779781
title: `Format Keywords`,
780-
html: createKeywordPanel(`keywords-${recordInfo.name}`, recordInfo.keywords),
782+
html: createKeywordPanel(`keywords-${recordInfo.name}`, recordInfo.keywords, (keywords) => {
783+
sendFormatHeaderUpdate(recordInfo.name, keywords);
784+
}),
781785
open: true
782786
});
783787

@@ -985,6 +989,18 @@ function sendFieldUpdate(recordFormat, originalFieldName, newFieldInfo) {
985989
}
986990
}
987991

992+
/**
993+
* @param {string} recordFormat
994+
* @param {Keyword[]} newKeywords
995+
*/
996+
function sendFormatHeaderUpdate(recordFormat, newKeywords) {
997+
vscode.postMessage({
998+
command: `updateFormat`,
999+
recordFormat,
1000+
newKeywords
1001+
});
1002+
}
1003+
9881004
/**
9891005
* Used to create panels for editable key/value lists.
9901006
* @param {string} id

0 commit comments

Comments
 (0)