Skip to content
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 33 additions & 10 deletions Extension/src/LanguageServer/editorConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
'use strict';

import * as fs from 'fs';
import { Minimatch } from 'minimatch';
import * as path from 'path';
import { isWindows } from '../constants';

export const cachedEditorConfigSettings: Map<string, any> = new Map<string, any>();

Expand Down Expand Up @@ -61,13 +63,25 @@
return "never";
}

function matchesSection(filePath: string, section: string): boolean {
const fileName: string = path.basename(filePath);
// Escape all regex special characters except '*' and '?'.
// Convert wildcards '*' to '.*' and '?' to '.'.
const sectionPattern = section.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.');
const regex: RegExp = new RegExp(`^${sectionPattern}$`);
return regex.test(fileName);
export function matchesSection(pathPrefix: string, filePath: string, section: string): boolean {
// The following code is copied from: https://github.com/editorconfig/editorconfig-core-js
const matchOptions = { matchBase: true, dot: true };
pathPrefix = pathPrefix.replace(/[?*+@!()|[\]{}]/g, '\\$&');
pathPrefix = pathPrefix.replace(/^#/, '\\#');
switch (section.indexOf('/')) {
case -1:
section = `**/${section}`;
break;
case 0:
section = section.substring(1);
break;
default:
break;
}
section = section.replace(/\\\\/g, '\\\\\\\\');
section = section.replace(/\*\*/g, '{*,**/**/**}');
const matcher = new Minimatch(`${pathPrefix}/${section}`, matchOptions);
return matcher.match(filePath);
}

function parseEditorConfigContent(content: string): Record<string, any> {
Expand Down Expand Up @@ -95,9 +109,9 @@
let value: any = values.join('=').trim();

// Convert boolean-like and numeric values.
if (value.toLowerCase() === 'true') {
if (value === 'true') {
value = true;
} else if (value.toLowerCase() === 'false') {
} else if (value === 'false') {
value = false;
} else if (!isNaN(Number(value))) {
value = Number(value);
Expand All @@ -123,6 +137,10 @@
let currentDir: string = path.dirname(filePath);
const rootDir: string = path.parse(currentDir).root;

if (isWindows) {
filePath = filePath.replace(/\\/g, '/');
}

// Traverse from the file's directory to the root directory.
for (; ;) {
const editorConfigPath: string = path.join(currentDir, '.editorconfig');
Expand All @@ -138,9 +156,14 @@
};
}

let currentDirForwardSlashes: string = currentDir;
if (isWindows) {
currentDirForwardSlashes = currentDir.replace(/\\/g, '/');
}

// Match sections and combine configurations.
Object.keys(configData).forEach((section: string) => {
if (section !== '*' && matchesSection(filePath, section)) {
if (section !== '*' && matchesSection(currentDirForwardSlashes, filePath, section)) {
combinedConfig = {
...combinedConfig,
...configData[section]
Expand Down
Loading