Skip to content

Commit

Permalink
Merge pull request #130 from mghdotdev/feature/flex-component-enhance…
Browse files Browse the repository at this point in the history
…ments

Feature/flex component enhancements
  • Loading branch information
mghdotdev authored Jan 9, 2025
2 parents fffb780 + 4c8758f commit 36447bf
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 15 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Miva IDE CHANGELOG

## v1.28.1 (latest)
## v1.29.0 (latest)

* Added variable autocompletion for flex instance templates.

## v1.28.1

* Fixed issue with changelog formatting.

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-miva-ide",
"displayName": "Miva IDE",
"description": "Syntax highlighting, snippets and tools for building websites with Miva.",
"version": "1.28.1",
"version": "1.29.0",
"engines": {
"vscode": "^1.77.0",
"node": ">=16"
Expand Down
23 changes: 21 additions & 2 deletions server/src/miva-features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {
import {
ActivationProviders,
LanguageFeatures,
MivaMangedTemplatesProviderCompletionType,
MivaScriptFunction,
MivaTemplateLanguageParsedFragment,
MivaTemplateLanguageParsedItem,
Expand Down Expand Up @@ -117,6 +118,8 @@ export function activateFeatures({workspaceSymbolProvider, mivaScriptCompilerPro

// Helper function for "variable" completion target list
const getVariableCompletions = (left: string, mivaDocument: TextDocument): CompletionList | null => {
const providerCompletionsAllTypes = mivaManagedTemplatesProvider?.provideCompletions(mivaDocument, MivaMangedTemplatesProviderCompletionType.Variable) || [];

// system variables
if ( patterns.SHARED.LEFT_VARIABLE_S.test( left ) ) {
return systemVariableCompletions;
Expand All @@ -135,7 +138,15 @@ export function activateFeatures({workspaceSymbolProvider, mivaScriptCompilerPro

const foundVariables = [].concat(
mivaDocumentText.match( patterns.SHARED.VARIABLES_G ) || [],
mivaDocumentText.match( patterns.MVT.ENTITIES_G ) || []
mivaDocumentText.match( patterns.MVT.ENTITIES_G ) || [],
providerCompletionsAllTypes
.map(completion => {
const matchedCompletion = completion.match(patterns.SHARED.LEFT_VARIABLE_G) || [];

if (matchedCompletion) {
return matchedCompletion[0] || '';
}
})
)
?.filter( unique )
?.filter(_variable => foundVariableRegex.test(_variable))
Expand Down Expand Up @@ -170,7 +181,15 @@ export function activateFeatures({workspaceSymbolProvider, mivaScriptCompilerPro
mivaDocumentText.match( patterns.SHARED.VARIABLES_L ) || [],
foundVariable.startsWith('settings')
? (mivaDocumentText.match( patterns.SHARED.VARIABLES_LSETTINGS ) || []).map(_variable => 'settings:' + _variable)
: []
: [],
providerCompletionsAllTypes
.map(completion => {
const matchedCompletion = completion.match(patterns.SHARED.LEFT_VARIABLE_L) || [];

if (matchedCompletion) {
return matchedCompletion[0] || '';
}
})
)
?.filter( unique )
?.filter(_variable => foundVariableRegex.test(_variable))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,55 @@
import { dirname, relative, resolve, sep } from 'path';
import { readFileSync } from 'fs';
import { dirname, join, relative, resolve, sep } from 'path';
import { DocumentLink, Range } from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { URI, Utils } from 'vscode-uri';
import { uriToFsPath } from '../../util/functions';
import { fileIsInFolder, walk } from '../../util/functions-node';
import { MivaTemplateLanguageParsedFragment, MivaTemplateLanguageParsedItem, Workspace } from '../../util/interfaces';
import { MivaMangedTemplatesProviderCompletionType, MivaTemplateLanguageParsedFragment, MivaTemplateLanguageParsedItem, Workspace } from '../../util/interfaces';

const buildFlexComponentPropertyPaths = (properties: any[], prefix: string, previousParent: string[] = []): string[] => {
let parent = previousParent;
let paths = [];

for (let property of properties) {
if (property.type === 'group') {
paths = paths.concat(buildFlexComponentPropertyPaths(property.properties, prefix, [...parent, property.code]));

}
else if (property.type === 'list') {
paths = paths.concat(finalizeFlexComponentPropertyPath([...parent, `${property.code}:children`], prefix, property.type), buildFlexComponentPropertyPaths(property.properties, prefix, [...parent, `${property.code}:children[1]`]));
}
else {
paths = paths.concat(finalizeFlexComponentPropertyPath([...parent, property.code], prefix, property.type));
}
}

return paths;
};

const finalizeFlexComponentPropertyPathSuffix = (type: string): string[] => {
switch (type) {
case 'link':
return [
'url',
'new_tab',
'type',
'value'
];

case 'list':
return [''];

default:
return ['value'];
}
};

const finalizeFlexComponentPropertyPath = (propertyPath: string[], prefix: string, type: string): string[] => {
const suffixes = finalizeFlexComponentPropertyPathSuffix(type);

return suffixes.map(suffix => `${prefix}:${propertyPath.join(':')}${suffix.length ? `:${suffix}` : ''}`);
};

export class MivaMangedTemplatesProvider {
private mmtPaths: Set<string> = new Set();
Expand Down Expand Up @@ -33,14 +78,22 @@ export class MivaMangedTemplatesProvider {
}
}

getFileContents (mmtPath: string, documentPath: string): string {
const fullPath = join(mmtPath, documentPath);

return readFileSync(fullPath, 'utf-8');
}

private getTargetFromRelativePath (relativePath: string, mmtPath: string): string {
return URI.parse(resolve(mmtPath, relativePath)).toString();
}

private getMmtPathParts (documentPath: string, mmtPath: string): string[] {
const relativePath = relative(mmtPath, documentPath);

return relativePath?.split(new RegExp(sep, 'g'));
return relativePath
?.split(new RegExp(sep, 'g'))
?.map(split => split?.toLowerCase());
}

async provideLinks (parsedItems: MivaTemplateLanguageParsedItem[], parsedFragments: MivaTemplateLanguageParsedFragment[], document: TextDocument): Promise<DocumentLink[]> {
Expand Down Expand Up @@ -334,4 +387,54 @@ export class MivaMangedTemplatesProvider {

return links;
}

provideCompletions (document: TextDocument, type: MivaMangedTemplatesProviderCompletionType): string[] {
const documentPath = uriToFsPath(document.uri);
const mmtPath = this.getPath(documentPath);
if (!mmtPath) {
return [];
}

const fileName = Utils.basename(URI.parse(document.uri))?.replace('.mvt', '')?.toLowerCase();
const [firstFolder] = this.getMmtPathParts(documentPath, mmtPath) ?? [];

const completions: string[] = [];

switch (type) {
case MivaMangedTemplatesProviderCompletionType.Variable: {
// Flex Components
if (firstFolder === 'templates') {
const flexComponentInstanceTemplatePrefix = 'flex-instance-template-';

if (fileName.startsWith(flexComponentInstanceTemplatePrefix)) {
// Isolate the flex component code
const flexComponentCode = fileName.replace(flexComponentInstanceTemplatePrefix, '');

if (flexComponentCode) {
const flexComponentJson = this.getFileContents(mmtPath, `properties/flex/${flexComponentCode}.json`);

if (flexComponentJson) {
const parsedFlexComponentJson = JSON.parse(flexComponentJson);

if (parsedFlexComponentJson) {
const propertyPaths = buildFlexComponentPropertyPaths(parsedFlexComponentJson.properties, 'l.settings:instance');
const advancedPropertyPaths = buildFlexComponentPropertyPaths(parsedFlexComponentJson.advanced_properties, 'l.settings:instance:advanced');

return [
...propertyPaths,
...advancedPropertyPaths
];
}
}
}
}
}

return completions;
}

default:
return completions;
}
}
}
16 changes: 10 additions & 6 deletions server/src/util/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export interface ActivationProviders {
workspaceSymbolProvider?: WorkspaceSymbolProvider,
mivaScriptCompilerProvider?: MivaScriptCompilerProvider,
mivaManagedTemplatesProvider?: MivaMangedTemplatesProvider
};
}

export interface LanguageFeatures {

Expand Down Expand Up @@ -98,7 +98,7 @@ export namespace ValidationCode {
export const GLOBAL_NULL_ASSIGNMENT = 'GLOBAL_NULL_ASSIGNMENT';
export const GLOBAL_ENCODING_ENTITY = 'GLOBAL_ENCODING_ENTITY';
export const GLOBAL_ENCODING_EVAL = 'GLOBAL_ENCODING_EVAL';
};
}
export type ValidationCode = 'NO_TOOLKIT' | 'NO_TOOLBELT' | 'FOREACH_LSETTINGS' | 'FOREACH_GLOBAL' | 'GLOBAL_NULL_ASSIGNMENT' | 'GLOBAL_ENCODING_ENTITY' | 'GLOBAL_ENCODING_EVAL';

export interface ValidationDataReplacement {
Expand All @@ -109,7 +109,7 @@ export interface ValidationDataReplacement {

export namespace ValidationDataType {
export const REPLACEMENT = 'REPLACEMENT';
};
}
export type ValidationDataType = 'REPLACEMENT';

export interface ValidationData {
Expand Down Expand Up @@ -280,23 +280,27 @@ export interface MivaScriptFunction {
parameters: string[];
description?: string;
returnValue?: string;
};
}

export interface MivaScriptFunctionFile {
distroPath: string;
functions: MivaScriptFunction[];
moduleCode?: string;
moduleVar?: string;
};
}

export interface MivaTemplateLanguageParsedItem {
name: string;
param?: string;
expression?: MivaExpression;
range?: Range;
};
}

export interface MivaTemplateLanguageParsedFragment {
code: string;
range: Range;
}

export enum MivaMangedTemplatesProviderCompletionType {
Variable
}

0 comments on commit 36447bf

Please sign in to comment.