Skip to content

Commit

Permalink
feat: add configuration for block marker regexes
Browse files Browse the repository at this point in the history
  • Loading branch information
1nVitr0 committed Apr 15, 2021
1 parent 27c4769 commit 86d0d77
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 26 deletions.
43 changes: 43 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,49 @@
"command": "blocksort.sortBlocksDesc",
"title": "Sort Blocks Descending"
}
],
"configuration": [
{
"title": "Block Sort",
"properties": {
"blocksort.indentIgnoreMarkers": {
"description": "Lines starting with these will not be taken into account when checking indentation. This is ised for C++-Style blocks ('{' in separate line) and for non-bracketed blocks (begin-end style). '{', 'end.*' and 'esac|fi' are already provided ('end.* is a bit more complicated, feel free to submit issued when some instances do not work)').",
"default": [],
"type": "array",
"items": {
"type": "string",
"format": "regex"
}
},
"blocksort.completeBlockMarkers": {
"description": "Lines ending with these will be handled as completed blocks (e.g. one line JSON objects). '}' and '</.*?>' are already provided (again '</.*?>' is a bit more complicated, feel free to submit issued when some instances do not work)",
"default": [],
"type": "array",
"items": {
"type": "string",
"format": "regex"
}
},
"blocksort.foldingMarkers": {
"description": "Folding markers used to detect folding. Blocks will only be completed if all folding is 0. '()', '[]', '{}' and '<>' are already provided",
"type": "object",
"default": {},
"additionalProperties": {
"type": "object",
"properties": {
"start": {
"type": "string",
"format": "regex"
},
"end": {
"type": "string",
"format": "regex"
}
}
}
}
}
}
]
},
"scripts": {
Expand Down
35 changes: 35 additions & 0 deletions src/providers/ConfigurationProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { workspace } from 'vscode';
import { FoldingMarkerDefault, FoldingMarkerList } from './StringProcessingProvider';

const defaultFoldingMarkers: FoldingMarkerList<FoldingMarkerDefault> = {
'()': { start: '\\(', end: '\\)' },
'[]': { start: '\\[', end: '\\]' },
'{}': { start: '\\{', end: '\\}' },
'<>': { start: '<[a-zA-Z0-9\\-_=\\s]+', end: '<\\/[a-zA-Z0-9\\-_=\\s]+' },
};

const defaultCompleteBlockMarkers = ['\\}', '<\\/[a-zA-Z0-9\\-_=\\s]+'];

const defaultIndentIgnoreMarkers = [
'{',
// eslint-disable-next-line quotes
"end(?:for(?:each)?|if|while|case|def)?\\s*?([\\.\\[\\->\\|\\s]\\s*(?:[$A-Za-z0-9_+\\-\\*\\/\\^\\%\\<\\>\\=\\!\\?\\:]*|'[^']*?'|'[']*?'|\"[^\"]*?\"|`[^`]*?`)\\s*[\\]\\|]?\\s*)*",
'esac|fi',
];

export default class ConfigurationProvider {
public static getFoldingMarkers(): FoldingMarkerList {
const additional: FoldingMarkerList = workspace.getConfiguration('blocksort').get('foldingMarkers') || {};
return { ...additional, ...defaultFoldingMarkers };
}

public static getCompleteBlockMarkers(): string[] {
const additional: string[] = workspace.getConfiguration('blocksort').get('completeBlockMarkers') || [];
return [...additional, ...defaultCompleteBlockMarkers];
}

public static getIndentIgnoreMarkers(): string[] {
const additional: string[] = workspace.getConfiguration('blocksort').get('indentIgnoreMarkers') || [];
return [...additional, ...defaultIndentIgnoreMarkers];
}
}
34 changes: 8 additions & 26 deletions src/providers/StringProcessingProvider.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Range, TextDocument, workspace } from 'vscode';
import { commentMarkers, commentRegex } from '../constants/comments';
import { stringMarkers } from '../constants/strings';
import ConfigurationProvider from './ConfigurationProvider';

type FoldingMarkerDefault = '()' | '[]' | '{}' | '<>';
type FoldingMarkerList<T extends string = string> = Record<
export type FoldingMarkerDefault = '()' | '[]' | '{}' | '<>';
export type FoldingMarkerList<T extends string = string> = Record<
T,
{ start: string; end: string; abortOnCurlyBrace?: boolean }
>;
Expand All @@ -15,37 +16,15 @@ export interface FoldingLevel {
}
export type Folding<T extends string = string> = { [marker in keyof FoldingMarkerList<T>]: FoldingLevel };

type FoldingMarkerOld = '()' | '[]' | '{}';
export type FoldingOld = Partial<Record<FoldingMarkerOld | '<>', number | null>> &
Record<FoldingMarkerOld, number | null>;

const foldingMarkers: FoldingMarkerList = {
'()': { start: '\\(', end: '\\)' },
'[]': { start: '\\[', end: '\\]' },
'{}': { start: '\\{', end: '\\}' },
'<>': { start: '<[a-zA-Z0-9\\-_=\\s]+', end: '<\\/[a-zA-Z0-9\\-_=\\s]+' },
};

const completeBlockMarkers = ['\\}', '<\\/[a-zA-Z0-9\\-_=\\s]+'];

const indentIgnoreMarkers = [
'{',
// eslint-disable-next-line quotes
"end(?:for(?:each)?|if|while|case|def)?\\s*?([\\.\\[\\->\\|\\s]\\s*(?:[$A-Za-z0-9_+\\-\\*\\/\\^\\%\\<\\>\\=\\!\\?\\:]*|'[^']*?'|'[']*?'|\"[^\"]*?\"|`[^`]*?`)\\s*[\\]\\|]?\\s*)*",
'esac|fi',
];

function initialFolding(): Folding {
const foldingMarkers = ConfigurationProvider.getFoldingMarkers();
return Object.keys(foldingMarkers).reduce<Folding>((r, key) => {
r[key] = { level: 0 };
return r;
}, {});
}

export default class StringProcessingProvider {
private static foldingMarkers: FoldingMarkerOld[] = ['()', '[]', '{}'];
private static useXmlFolding = ['html', 'jsx', 'xml'];

private document: TextDocument;

public constructor(document: TextDocument) {
Expand Down Expand Up @@ -77,6 +56,7 @@ export default class StringProcessingProvider {
}

public getFolding(text: string, initial: Folding = initialFolding(), validate = false): Folding {
const foldingMarkers = ConfigurationProvider.getFoldingMarkers();
const result: Folding = { ...initial };

const lines = text.split(/\r?\n/);
Expand All @@ -88,7 +68,7 @@ export default class StringProcessingProvider {
const sanitized = this.stripStrings(this.stripComments(line)).trim();
for (const key of Object.keys(foldingMarkers)) {
const folding = result[key] || { level: 0 };
const { start, end, abortOnCurlyBrace } = foldingMarkers[key];
const { start, end } = foldingMarkers[key];

const open = sanitized.split(new RegExp(start)).length - 1;
const close = sanitized.split(new RegExp(end)).length - 1;
Expand Down Expand Up @@ -117,12 +97,14 @@ export default class StringProcessingProvider {
}

public isIndentIgnoreLine(line: string): boolean {
const indentIgnoreMarkers = ConfigurationProvider.getIndentIgnoreMarkers();
const comment = commentRegex[this.document.languageId || 'default'] || commentRegex.default;
const indentIgnoreRegex = `^\\s*(?:${indentIgnoreMarkers.join('|')})(?:${comment}|\\s*)*$`;
return new RegExp(indentIgnoreRegex).test(line);
}

public isCompleteBlock(block: string): boolean {
const completeBlockMarkers = ConfigurationProvider.getCompleteBlockMarkers();
const comment = commentRegex[this.document.languageId || 'default'] || commentRegex.default;
const completeBlockRegex = `(?:${completeBlockMarkers.join('|')})(?:,|;)?(?:${comment}|\\s*)*(?:,|;)?$`;
return new RegExp(completeBlockRegex, 'g').test(block);
Expand Down

0 comments on commit 86d0d77

Please sign in to comment.