Skip to content

Commit

Permalink
Feature/remove seqjson and seqn lang specifics (#1446)
Browse files Browse the repository at this point in the history
* Moved the lint calls outside of lang specific files

* Added a default adaptation and hooks for auto indent and auto complete

* Fixed filterText not having a type and reconfiguring the sequence editor

* Removed a lint problem

* Fixed an issue where reconfiguring the seqn editor was throwing away all extensions

* Moved auto complete to a comparment
  • Loading branch information
cohansen authored Sep 23, 2024
1 parent 8e4253f commit 78d20f3
Show file tree
Hide file tree
Showing 8 changed files with 1,490 additions and 1,306 deletions.
60 changes: 30 additions & 30 deletions src/components/sequencing/SequenceEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@
import { setupLanguageSupport } from '../../utilities/codemirror';
import effects from '../../utilities/effects';
import { downloadBlob, downloadJSON } from '../../utilities/generic';
import { seqJsonLinter } from '../../utilities/sequence-editor/seq-json-linter';
import { sequenceAutoIndent } from '../../utilities/sequence-editor/sequence-autoindent';
import { sequenceCompletion } from '../../utilities/sequence-editor/sequence-completion';
import { sequenceLinter } from '../../utilities/sequence-editor/sequence-linter';
import { inputLinter, outputLinter } from '../../utilities/sequence-editor/extension-points';
import { sequenceTooltip } from '../../utilities/sequence-editor/sequence-tooltip';
import { showFailureToast, showSuccessToast } from '../../utilities/toast';
import { tooltip } from '../../utilities/tooltip';
Expand Down Expand Up @@ -73,6 +70,7 @@
let compartmentSeqLanguage: Compartment;
let compartmentSeqLinter: Compartment;
let compartmentSeqTooltip: Compartment;
let compartmentSeqAutocomplete: Compartment;
let channelDictionary: ChannelDictionary | null;
let commandDictionary: CommandDictionary | null;
let disableCopyAndExport: boolean = true;
Expand All @@ -88,11 +86,6 @@
let selectedOutputFormat: IOutputFormat | undefined;
let toggleSeqJsonPreview: boolean = false;
$: {
outputFormats = $outputFormat;
selectedOutputFormat = outputFormats[0];
}
$: {
loadSequenceAdaptation(parcel?.sequence_adaptation_id);
}
Expand Down Expand Up @@ -154,26 +147,29 @@
// Reconfigure sequence editor.
editorSequenceView.dispatch({
effects: compartmentSeqLanguage.reconfigure(
setupLanguageSupport(
sequenceCompletion(parsedChannelDictionary, parsedCommandDictionary, nonNullParsedParameterDictionaries),
effects: [
compartmentSeqLanguage.reconfigure(
setupLanguageSupport(
$sequenceAdaptation.autoComplete(
parsedChannelDictionary,
parsedCommandDictionary,
nonNullParsedParameterDictionaries,
),
),
),
),
});
editorSequenceView.dispatch({
effects: compartmentSeqLinter.reconfigure(
sequenceLinter(parsedChannelDictionary, parsedCommandDictionary, nonNullParsedParameterDictionaries),
),
});
editorSequenceView.dispatch({
effects: compartmentSeqTooltip.reconfigure(
sequenceTooltip(parsedChannelDictionary, parsedCommandDictionary, nonNullParsedParameterDictionaries),
),
compartmentSeqLinter.reconfigure(
inputLinter(parsedChannelDictionary, parsedCommandDictionary, nonNullParsedParameterDictionaries),
),
compartmentSeqTooltip.reconfigure(
sequenceTooltip(parsedChannelDictionary, parsedCommandDictionary, nonNullParsedParameterDictionaries),
),
compartmentSeqAutocomplete.reconfigure(indentService.of($sequenceAdaptation.autoIndent())),
],
});
// Reconfigure seq JSON editor.
editorOutputView.dispatch({
effects: compartmentSeqJsonLinter.reconfigure(seqJsonLinter(parsedCommandDictionary, selectedOutputFormat)),
effects: compartmentSeqJsonLinter.reconfigure(outputLinter(parsedCommandDictionary, selectedOutputFormat)),
});
});
}
Expand All @@ -184,6 +180,7 @@
compartmentSeqLanguage = new Compartment();
compartmentSeqLinter = new Compartment();
compartmentSeqTooltip = new Compartment();
compartmentSeqAutocomplete = new Compartment();
editorSequenceView = new EditorView({
doc: sequenceDefinition,
Expand All @@ -192,12 +189,12 @@
EditorView.lineWrapping,
EditorView.theme({ '.cm-gutter': { 'min-height': `${clientHeightGridRightTop}px` } }),
lintGutter(),
compartmentSeqLanguage.of(setupLanguageSupport(sequenceCompletion(null, null, []))),
compartmentSeqLinter.of(sequenceLinter()),
compartmentSeqLanguage.of(setupLanguageSupport($sequenceAdaptation.autoComplete(null, null, []))),
compartmentSeqLinter.of(inputLinter()),
compartmentSeqTooltip.of(sequenceTooltip()),
EditorView.updateListener.of(debounce(sequenceUpdateListener, 250)),
EditorView.updateListener.of(selectedCommandUpdateListener),
indentService.of(sequenceAutoIndent()),
compartmentSeqAutocomplete.of(indentService.of($sequenceAdaptation.autoIndent())),
EditorState.readOnly.of(readOnly),
],
parent: editorSequenceDiv,
Expand All @@ -212,7 +209,7 @@
EditorView.editable.of(false),
lintGutter(),
json(),
compartmentSeqJsonLinter.of(seqJsonLinter()),
compartmentSeqJsonLinter.of(outputLinter()),
EditorState.readOnly.of(readOnly),
],
parent: editorOutputDiv,
Expand All @@ -238,6 +235,9 @@
} else {
resetSequenceAdaptation();
}
outputFormats = $outputFormat;
selectedOutputFormat = outputFormats[0];
}
function resetSequenceAdaptation(): void {
Expand Down Expand Up @@ -278,14 +278,14 @@
const fileExtension = `${sequenceName}.${selectedOutputFormat?.fileExtension}`;
if (outputFormat?.fileExtension === 'json') {
downloadJSON(editorOutputView.state.doc.toJSON(), fileExtension);
downloadJSON(JSON.parse(editorOutputView.state.doc.toString()), fileExtension);
} else {
downloadBlob(new Blob([editorOutputView.state.doc.toString()], { type: 'text/plain' }), fileExtension);
}
}
function downloadInputFormat() {
downloadBlob(new Blob([editorOutputView.state.doc.toString()], { type: 'text/plain' }), `${sequenceName}.txt`);
downloadBlob(new Blob([editorSequenceView.state.doc.toString()], { type: 'text/plain' }), `${sequenceName}.txt`);
}
async function copyOutputFormatToClipboard() {
Expand Down
4 changes: 2 additions & 2 deletions src/components/sequencing/Sequences.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
export let user: User | null;
let filterText = '';
let filterText: string = '';
let parcel: Parcel | null;
let selectedSequence: UserSequence | null = null;
let workspace: Workspace | undefined;
Expand All @@ -32,7 +32,7 @@
$: parcel = $parcels.find(p => p.id === selectedSequence?.parcel_id) ?? null;
$: workspace = $workspaces.find(workspace => workspace.id === workspaceId);
$: if (selectedSequence !== null) {
const found = $userSequences.findIndex(sequence => sequence.id === selectedSequence?.id);
const found: number = $userSequences.findIndex(sequence => sequence.id === selectedSequence?.id);
if (found === -1) {
selectedSequence = null;
Expand Down
2 changes: 1 addition & 1 deletion src/components/workspace/WorkspaceTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
export let user: User | null;
let baseColumnDefs: DataGridColumnDef[];
let filterText = '';
let filterText: string = '';
let filteredWorkspaces: Workspace[] = [];
let selectedWorkspace: Workspace | null = null;
Expand Down
79 changes: 55 additions & 24 deletions src/stores/sequence-adaptation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,47 @@ import type { GlobalType } from '../types/global-type';
import type { ISequenceAdaptation, SequenceAdaptation } from '../types/sequencing';
import gql from '../utilities/gql';
import { seqJsonToSequence } from '../utilities/sequence-editor/from-seq-json';
import { sequenceAutoIndent } from '../utilities/sequence-editor/sequence-autoindent';
import { sequenceCompletion } from '../utilities/sequence-editor/sequence-completion';
import { sequenceToSeqJson } from '../utilities/sequence-editor/to-seq-json';
import { gqlSubscribable } from './subscribable';

const defaultAdaptation: ISequenceAdaptation = {
argDelegator: undefined,
autoComplete: sequenceCompletion,
autoIndent: sequenceAutoIndent,
conditionalKeywords: {
else: 'CMD_ELSE',
elseIf: ['CMD_ELSE_IF'],
endIf: 'CMD_END_IF',
if: ['CMD_IF'],
},
globals: [],
inputFormat: {
linter: undefined,
name: 'SeqN',
toInputFormat: seqJsonToSequence,
},
loopKeywords: {
break: 'CMD_BREAK',
continue: 'CMD_CONTINUE',
endWhileLoop: 'CMD_END_WHILE_LOOP',
whileLoop: ['CMD_WHILE_LOOP', 'CMD_WHILE_LOOP_OR'],
},
modifyOutput: undefined,
modifyOutputParse: undefined,
outputFormat: [
{
fileExtension: 'json',
name: 'Seq JSON',
toOutputFormat: sequenceToSeqJson,
},
],
};

/* Writeable */

export const sequenceAdaptation: Writable<ISequenceAdaptation | undefined> = writable(undefined);
export const sequenceAdaptation: Writable<ISequenceAdaptation> = writable(defaultAdaptation);

/* Subscriptions. */

Expand All @@ -26,38 +61,34 @@ export const outputFormat = derived(
/* Helpers */

export function getGlobals(): GlobalType[] {
return get(sequenceAdaptation)?.globals ?? [];
return get(sequenceAdaptation).globals ?? [];
}

export function setSequenceAdaptation(newSequenceAdaptation: ISequenceAdaptation | undefined): void {
sequenceAdaptation.set({
argDelegator: newSequenceAdaptation?.argDelegator ?? undefined,
argDelegator: newSequenceAdaptation?.argDelegator ?? defaultAdaptation.argDelegator,
autoComplete: newSequenceAdaptation?.autoComplete ?? defaultAdaptation.autoComplete,
autoIndent: newSequenceAdaptation?.autoIndent ?? defaultAdaptation.autoIndent,
conditionalKeywords: {
else: newSequenceAdaptation?.conditionalKeywords?.else ?? 'CMD_ELSE',
elseIf: newSequenceAdaptation?.conditionalKeywords?.elseIf ?? ['CMD_ELSE_IF'],
endIf: newSequenceAdaptation?.conditionalKeywords?.endIf ?? 'CMD_END_IF',
if: newSequenceAdaptation?.conditionalKeywords?.if ?? ['CMD_IF'],
else: newSequenceAdaptation?.conditionalKeywords?.else ?? defaultAdaptation.conditionalKeywords.else,
elseIf: newSequenceAdaptation?.conditionalKeywords?.elseIf ?? defaultAdaptation.conditionalKeywords.elseIf,
endIf: newSequenceAdaptation?.conditionalKeywords?.endIf ?? defaultAdaptation.conditionalKeywords.endIf,
if: newSequenceAdaptation?.conditionalKeywords?.if ?? defaultAdaptation.conditionalKeywords.if,
},
globals: newSequenceAdaptation?.globals ?? [],
globals: newSequenceAdaptation?.globals ?? defaultAdaptation.globals,
inputFormat: {
linter: newSequenceAdaptation?.inputFormat?.linter ?? undefined,
name: newSequenceAdaptation?.inputFormat?.name ?? 'SeqN',
toInputFormat: newSequenceAdaptation?.inputFormat?.toInputFormat ?? seqJsonToSequence,
linter: newSequenceAdaptation?.inputFormat?.linter ?? defaultAdaptation.inputFormat.linter,
name: newSequenceAdaptation?.inputFormat?.name ?? defaultAdaptation.inputFormat.name,
toInputFormat: newSequenceAdaptation?.inputFormat?.toInputFormat ?? defaultAdaptation.inputFormat.toInputFormat,
},
loopKeywords: {
break: newSequenceAdaptation?.loopKeywords?.break ?? 'CMD_BREAK',
continue: newSequenceAdaptation?.loopKeywords?.continue ?? 'CMD_CONTINUE',
endWhileLoop: newSequenceAdaptation?.loopKeywords?.endWhileLoop ?? 'CMD_END_WHILE_LOOP',
whileLoop: newSequenceAdaptation?.loopKeywords?.whileLoop ?? ['CMD_WHILE_LOOP', 'CMD_WHILE_LOOP_OR'],
break: newSequenceAdaptation?.loopKeywords?.break ?? defaultAdaptation.loopKeywords.break,
continue: newSequenceAdaptation?.loopKeywords?.continue ?? defaultAdaptation.loopKeywords.continue,
endWhileLoop: newSequenceAdaptation?.loopKeywords?.endWhileLoop ?? defaultAdaptation.loopKeywords.endWhileLoop,
whileLoop: newSequenceAdaptation?.loopKeywords?.whileLoop ?? defaultAdaptation.loopKeywords.whileLoop,
},
modifyOutput: newSequenceAdaptation?.modifyOutput ?? undefined,
modifyOutputParse: newSequenceAdaptation?.modifyOutputParse ?? undefined,
outputFormat: newSequenceAdaptation?.outputFormat ?? [
{
fileExtension: 'json',
name: 'Seq JSON',
toOutputFormat: sequenceToSeqJson,
},
],
modifyOutput: newSequenceAdaptation?.modifyOutput ?? defaultAdaptation.modifyOutput,
modifyOutputParse: newSequenceAdaptation?.modifyOutputParse ?? defaultAdaptation.modifyOutputParse,
outputFormat: newSequenceAdaptation?.outputFormat ?? defaultAdaptation.outputFormat,
});
}
8 changes: 8 additions & 0 deletions src/types/sequencing.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
import type { IndentContext } from '@codemirror/language';
import type { Diagnostic } from '@codemirror/lint';
import type { SyntaxNode } from '@lezer/common';
import type {
Expand Down Expand Up @@ -57,6 +59,12 @@ export interface IOutputFormat {

export interface ISequenceAdaptation {
argDelegator?: ArgDelegator;
autoComplete: (
channelDictionary: AmpcsChannelDictionary | null,
commandDictionary: AmpcsCommandDictionary | null,
parameterDictionaries: AmpcsParameterDictionary[],
) => (context: CompletionContext) => CompletionResult | null;
autoIndent: () => (context: IndentContext, pos: number) => number | null | undefined;
conditionalKeywords: { else: string; elseIf: string[]; endIf: string; if: string[] };
globals?: GlobalType[];
inputFormat: {
Expand Down
60 changes: 56 additions & 4 deletions src/utilities/sequence-editor/extension-points.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { type ChannelDictionary, type FswCommandArgument, type ParameterDictionary } from '@nasa-jpl/aerie-ampcs';
import { syntaxTree } from '@codemirror/language';
import { linter, type Diagnostic } from '@codemirror/lint';
import type { Extension } from '@codemirror/state';
import {
type ChannelDictionary,
type CommandDictionary,
type FswCommandArgument,
type ParameterDictionary,
} from '@nasa-jpl/aerie-ampcs';
import { get } from 'svelte/store';
import { inputFormat, sequenceAdaptation } from '../../stores/sequence-adaptation';
import type { IOutputFormat } from '../../types/sequencing';
import { seqJsonLinter } from './seq-json-linter';
import { sequenceLinter } from './sequence-linter';

// TODO: serialization
// replace parameter names with hex ids
Expand Down Expand Up @@ -30,8 +41,8 @@ export function getCustomArgDef(
) {
let delegate = undefined;

if (get(sequenceAdaptation)?.argDelegator !== undefined) {
delegate = get(sequenceAdaptation)?.argDelegator?.[stem]?.[dictArg.name];
if (get(sequenceAdaptation).argDelegator !== undefined) {
delegate = get(sequenceAdaptation).argDelegator?.[stem]?.[dictArg.name];
}

return delegate?.(dictArg, parameterDictionaries, channelDictionary, precedingArgs) ?? dictArg;
Expand All @@ -42,7 +53,7 @@ export async function toInputFormat(
parameterDictionaries: ParameterDictionary[],
channelDictionary: ChannelDictionary | null,
) {
const modifyOutputParse = get(sequenceAdaptation)?.modifyOutputParse;
const modifyOutputParse = get(sequenceAdaptation).modifyOutputParse;
let modifiedOutput = null;

if (modifyOutputParse !== undefined) {
Expand All @@ -53,3 +64,44 @@ export async function toInputFormat(

return input;
}

export function inputLinter(
channelDictionary: ChannelDictionary | null = null,
commandDictionary: CommandDictionary | null = null,
parameterDictionaries: ParameterDictionary[] = [],
): Extension {
return linter(view => {
const inputLinter = get(sequenceAdaptation).inputFormat.linter;
const tree = syntaxTree(view.state);
const treeNode = tree.topNode;
let diagnostics: Diagnostic[];

diagnostics = sequenceLinter(view, channelDictionary, commandDictionary, parameterDictionaries);

if (inputLinter !== undefined && commandDictionary !== null) {
diagnostics = inputLinter(diagnostics, commandDictionary, view, treeNode);
}

return diagnostics;
});
}

export function outputLinter(
commandDictionary: CommandDictionary | null = null,
outputFormat: IOutputFormat | undefined = undefined,
): Extension {
return linter(view => {
const tree = syntaxTree(view.state);
const treeNode = tree.topNode;
const outputLinter = outputFormat?.linter;
let diagnostics: Diagnostic[];

diagnostics = seqJsonLinter(view, commandDictionary);

if (outputLinter !== undefined && commandDictionary !== null) {
diagnostics = outputLinter(diagnostics, commandDictionary, view, treeNode);
}

return diagnostics;
});
}
Loading

0 comments on commit 78d20f3

Please sign in to comment.