Skip to content

Commit

Permalink
feat: contribute configuration for natural sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
1nVitr0 committed Jun 14, 2021
1 parent a2bf771 commit 0b61216
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 32 deletions.
38 changes: 38 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,44 @@
}
}
},
"blocksort.enableNaturalSorting": {
"type": "boolean",
"description": "Sort string containing numbers intuitively (`80` before `443`)",
"default": false
},
"blocksort.naturalSorting": {
"type": "object",
"description": "Settings for natural sorting",
"default": {
"enabled": false,
"padding": 9,
"omitUuids": false,
"sortNegativeValues": true
},
"required": [
"enabled"
],
"additionalProperties": false,
"properties": {
"padding": {
"description": "For natural sorting numbers are padded with 0. For performance reasons the number of 0s is fixed to this value",
"default": 9,
"type": "number",
"minimum": "0",
"maximum": "16"
},
"omitUuids": {
"description": "Enables very basic UUID detection and automatically disables natural sorting for these values. Might still fail for edge cases (like a number at the end of the UUID or on dashes)",
"default": false,
"type": "boolean"
},
"sortNegativeValues": {
"description": "Sort negative values before positive. Might fail, especially on UUIDs containing dashes",
"default": true,
"type": "boolean"
}
}
},
"blocksort.sortConsecutiveBlockHeaders": {
"description": "sort consecutive block headers (such as case or when)",
"type": "boolean",
Expand Down
12 changes: 8 additions & 4 deletions src/commands/blockSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,21 @@ function blockSortMultilevel(sortFunction: (a: string, b: string) => number) {
}

export function blockSortAsc(editor: TextEditor, editBuilder: TextEditorEdit) {
blockSort(editor, editBuilder, BlockSortProvider.sort.asc);
const naturalSorting = ConfigurationProvider.getEnableNaturalSorting();
blockSort(editor, editBuilder, naturalSorting ? BlockSortProvider.sort.ascNatural : BlockSortProvider.sort.asc);
}

export function blockSortDesc(editor: TextEditor, editBuilder: TextEditorEdit) {
blockSort(editor, editBuilder, BlockSortProvider.sort.desc);
const naturalSorting = ConfigurationProvider.getEnableNaturalSorting();
blockSort(editor, editBuilder, naturalSorting ? BlockSortProvider.sort.descNatural : BlockSortProvider.sort.desc);
}

export function blockSortMultilevelAsc() {
blockSortMultilevel(BlockSortProvider.sort.asc);
const naturalSorting = ConfigurationProvider.getEnableNaturalSorting();
blockSortMultilevel(naturalSorting ? BlockSortProvider.sort.ascNatural : BlockSortProvider.sort.asc);
}

export function blockSortMultilevelDesc() {
blockSortMultilevel(BlockSortProvider.sort.desc);
const naturalSorting = ConfigurationProvider.getEnableNaturalSorting();
blockSortMultilevel(naturalSorting ? BlockSortProvider.sort.descNatural : BlockSortProvider.sort.desc);
}
13 changes: 6 additions & 7 deletions src/providers/BlockSortProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ export default class BlockSortProvider {
BlockSortProvider.sort.desc(BlockSortProvider.padNumbers(a), BlockSortProvider.padNumbers(b)),
};
protected static padNumbers(line: string) {
const pad = /*naturalSortPadding*/ 16;
const { omitUuids, padding, sortNegativeValues } = ConfigurationProvider.getNaturalSortOptions();
let result = line;
if (/*detectUuids*/ true)
result = result.replace(/\d+(?=[^a-zA-z]|$)|(?<=[^a-zA-z]|^)\d+/g, (match) => match.padStart(pad, "0"));
else result = result.replace(/\d+/g, (match) => match.padStart(pad, "0"));
if (omitUuids) result = result.replace(/\d+(?=[^a-zA-z]|$)|(?<=[^a-zA-z]|^)\d+/g, (match) => match.padStart(padding, "0"));
else result = result.replace(/\d+/g, (match) => match.padStart(padding, "0"));

if (/*negative values*/ true) {
if (sortNegativeValues) {
result = result.replace(
new RegExp(`-\\d{${pad}}`, "g"),
(match) => `-${(Math.pow(10, pad) + parseInt(match)).toString()}`
new RegExp(`-\\d{${padding}}`, "g"),
(match) => `-${(Math.pow(10, padding) + parseInt(match)).toString()}`
);
}

Expand Down
62 changes: 42 additions & 20 deletions src/providers/ConfigurationProvider.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,90 @@
import { workspace } from 'vscode';
import { FoldingMarkerDefault, FoldingMarkerList } from './StringProcessingProvider';
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]+' },
"()": { 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 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',
"esac|fi",
];

export interface NaturalSortOptions {
enabled: boolean;
padding: number;
omitUuids: boolean;
sortNegativeValues: boolean;
}

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

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

public static getSortConsecutiveBlockHeaders(): boolean {
const configuration: boolean | undefined = workspace
.getConfiguration('blocksort')
.get('sortConsecutiveBlockHeaders');
.getConfiguration("blocksort")
.get("sortConsecutiveBlockHeaders");
return configuration === undefined ? true : configuration;
}

public static getDefaultMultilevelDepth(): number {
const configuration: number | undefined = workspace.getConfiguration('blocksort').get('defaultMultilevelDepth');
const configuration: number | undefined = workspace.getConfiguration("blocksort").get("defaultMultilevelDepth");
return configuration === undefined ? -1 : configuration;
}

public static getAskForMultilevelDepth(): boolean {
const configuration: boolean | undefined = workspace.getConfiguration('blocksort').get('askForMultilevelDepth');
const configuration: boolean | undefined = workspace.getConfiguration("blocksort").get("askForMultilevelDepth");
return configuration === undefined ? true : configuration;
}

public static getForceBlockHeaderFirstRegex(): string {
return '$^';
return "$^";
}

public static getForceBlockHeaderLastRegex(): string {
return '(default|else)\\s*(\'([^\']|(?<=\\\\)\')*\'|"([^"]|(?<=\\\\)")*"|`([^`]|(?<=\\\\)`)*`|[A-Za-z_+\\-*/%<>d.,s]*)*\\s*(.*:)?(\r?\n|$)';
return "(default|else)\\s*('([^']|(?<=\\\\)')*'|\"([^\"]|(?<=\\\\)\")*\"|`([^`]|(?<=\\\\)`)*`|[A-Za-z_+\\-*/%<>d.,s]*)*\\s*(.*:)?(\r?\n|$)";
}

public static getMultiBlockHeaderRegex(): string {
return '(when|case|else|default)\\s*(\'([^\']|(?<=\\\\)\')*\'|"([^"]|(?<=\\\\)")*"|`([^`]|(?<=\\\\)`)*`|[A-Za-z_+\\-*/%<>d.,s]*)*\\s*(.*:)?$';
return "(when|case|else|default)\\s*('([^']|(?<=\\\\)')*'|\"([^\"]|(?<=\\\\)\")*\"|`([^`]|(?<=\\\\)`)*`|[A-Za-z_+\\-*/%<>d.,s]*)*\\s*(.*:)?$";
}

public static getIncompleteBlockRegex(): string {
return '(if|when|else|case|for|foreach|else|elsif|while|def|then)\\s*(\'([^\']|(?<=\\\\)\')*\'|"([^"]|(?<=\\\\)")*"|`([^`]|(?<=\\\\)`)*`|[A-Za-z_+\\-*/%<>d.,s]*)*\\s*(.*:)?$';
return "(if|when|else|case|for|foreach|else|elsif|while|def|then)\\s*('([^']|(?<=\\\\)')*'|\"([^\"]|(?<=\\\\)\")*\"|`([^`]|(?<=\\\\)`)*`|[A-Za-z_+\\-*/%<>d.,s]*)*\\s*(.*:)?$";
}

public static getIndentIgnoreMarkers(): string[] {
const additional: string[] = workspace.getConfiguration('blocksort').get('indentIgnoreMarkers') || [];
const additional: string[] = workspace.getConfiguration("blocksort").get("indentIgnoreMarkers") || [];
return [...additional, ...defaultIndentIgnoreMarkers];
}

public static getNaturalSortOptions(): NaturalSortOptions {
const configuration: Partial<NaturalSortOptions> = workspace.getConfiguration("blocksort").get("naturalSorting") || {};
return {
enabled: false,
padding: 9,
omitUuids: false,
sortNegativeValues: true,
...configuration
};
}

public static getEnableNaturalSorting(): boolean {
return !!workspace.getConfiguration("blocksort").get("enableNaturalSorting");
}
}
2 changes: 1 addition & 1 deletion src/test/fixtures/natural.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ export const naturalSortTests: SortTest[] = [
{
file: 'natural.txt.fixture',
compareFile: 'natural.txt.expect',
ranges: [new Range(0, 0, 4, 4), new Range(6, 0, 9, 9)],
ranges: [new Range(0, 0, 4, 4), new Range(6, 0, 9, 9), new Range(11, 0, 17, 5)],
},
];
8 changes: 8 additions & 0 deletions test/fixtures/natural.txt.expect
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ port 22
port 80
port 443
port 8080

-3456
-12
2
19
60
145
1837
8 changes: 8 additions & 0 deletions test/fixtures/natural.txt.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ port 443
port 80
port 8080
port 22

145
2
19
-12
1837
60
-3456

0 comments on commit 0b61216

Please sign in to comment.