Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 0 additions & 2 deletions Extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6505,7 +6505,6 @@
"@vscode/test-electron": "^2.3.10",
"async-child-process": "^1.1.1",
"await-notify": "^1.0.1",
"copy-webpack-plugin": "^12.0.2",
"eslint": "^8.45.0",
"eslint-plugin-header": "^3.1.1",
"eslint-plugin-import": "^2.29.1",
Expand Down Expand Up @@ -6534,7 +6533,6 @@
"@vscode/extension-telemetry": "^0.9.6",
"chokidar": "^3.6.0",
"comment-json": "^4.2.3",
"editorconfig": "^2.0.0",
"escape-string-regexp": "^2.0.0",
"glob": "^7.2.3",
"minimatch": "^3.0.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import * as vscode from 'vscode';
import { ResponseError } from 'vscode-languageclient';
import { DefaultClient, FormatDocumentRequest, FormatParams, FormatResult } from '../client';
import { getEditorConfigSettings } from '../editorConfig';
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
import { CppSettings, OtherSettings, getEditorConfigSettings } from '../settings';
import { CppSettings, OtherSettings } from '../settings';
import { makeVscodeTextEdits } from '../utils';

export class DocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import * as vscode from 'vscode';
import { ResponseError } from 'vscode-languageclient';
import { DefaultClient, FormatParams, FormatRangeRequest, FormatResult } from '../client';
import { getEditorConfigSettings } from '../editorConfig';
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
import { CppSettings, getEditorConfigSettings } from '../settings';
import { CppSettings } from '../settings';
import { makeVscodeTextEdits } from '../utils';

export class DocumentRangeFormattingEditProvider implements vscode.DocumentRangeFormattingEditProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import * as vscode from 'vscode';
import { ResponseError } from 'vscode-languageclient';
import { DefaultClient, FormatOnTypeRequest, FormatParams, FormatResult } from '../client';
import { getEditorConfigSettings } from '../editorConfig';
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
import { CppSettings, getEditorConfigSettings } from '../settings';
import { CppSettings } from '../settings';
import { makeVscodeTextEdits } from '../utils';

export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEditProvider {
Expand Down
4 changes: 2 additions & 2 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ import {
import { Location, TextEdit, WorkspaceEdit } from './commonTypes';
import * as configs from './configurations';
import { DataBinding } from './dataBinding';
import { cachedEditorConfigSettings, getEditorConfigSettings } from './editorConfig';
import { CppSourceStr, clients, configPrefix, updateLanguageConfigurations, usesCrashHandler, watchForCrashes } from './extension';
import { LocalizeStringParams, getLocaleId, getLocalizedString } from './localization';
import { PersistentFolderState, PersistentWorkspaceState } from './persistentState';
import { createProtocolFilter } from './protocolFilter';
import * as refs from './references';
import { CppSettings, OtherSettings, SettingsParams, WorkspaceFolderSettingsParams, getEditorConfigSettings } from './settings';
import { CppSettings, OtherSettings, SettingsParams, WorkspaceFolderSettingsParams } from './settings';
import { SettingsTracker } from './settingsTracker';
import { ConfigurationType, LanguageStatusUI, getUI } from './ui';
import { handleChangedFromCppToC, makeLspRange, makeVscodeLocation, makeVscodeRange } from './utils';
Expand Down Expand Up @@ -102,7 +103,6 @@ let workspaceHash: string = "";
let workspaceDisposables: vscode.Disposable[] = [];
export let workspaceReferences: refs.ReferencesManager;
export const openFileVersions: Map<string, number> = new Map<string, number>();
export const cachedEditorConfigSettings: Map<string, any> = new Map<string, any>();
export const cachedEditorConfigLookups: Map<string, boolean> = new Map<string, boolean>();
export let semanticTokensLegend: vscode.SemanticTokensLegend | undefined;

Expand Down
168 changes: 168 additions & 0 deletions Extension/src/LanguageServer/editorConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';

import * as fs from 'fs';
import * as path from 'path';

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

export function mapIndentationReferenceToEditorConfig(value: string | undefined): string {
if (value !== undefined) {
// Will never actually be undefined, as these settings have default values.
if (value === "statementBegin") {
return "statement_begin";
}
if (value === "outermostParenthesis") {
return "outermost_parenthesis";
}
}
return "innermost_parenthesis";
}

export function mapIndentToEditorConfig(value: string | undefined): string {
if (value !== undefined) {
// Will never actually be undefined, as these settings have default values.
if (value === "leftmostColumn") {
return "leftmost_column";
}
if (value === "oneLeft") {
return "one_left";
}
}
return "none";
}

export function mapNewOrSameLineToEditorConfig(value: string | undefined): string {
if (value !== undefined) {
// Will never actually be undefined, as these settings have default values.
if (value === "newLine") {
return "new_line";
}
if (value === "sameLine") {
return "same_line";
}
}
return "ignore";
}

export function mapWrapToEditorConfig(value: string | undefined): string {
if (value !== undefined) {
// Will never actually be undefined, as these settings have default values.
if (value === "allOneLineScopes") {
return "all_one_line_scopes";
}
if (value === "oneLiners") {
return "one_liners";
}
}
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);
}

function parseEditorConfigContent(content: string): Record<string, any> {
const lines = content.split(/\r?\n/);
const config: Record<string, any> = {};
let currentSection: string | null = '*'; // Use '*' for sectionless (global) settings.

lines.forEach(line => {
line = line.trim();

if (!line || line.startsWith('#') || line.startsWith(';')) {
// Skip empty lines and comments.
return;
}

if (line.startsWith('[') && line.endsWith(']')) {
// New section (e.g., [*.js])
currentSection = line.slice(1, -1).trim();
config[currentSection] = config[currentSection] || {};
} else {
// Key-value pair (e.g., indent_style = space).
const [key, ...values] = line.split('=');
if (key && values.length > 0) {
const trimmedKey = key.trim();
const value = values.join('=').trim();
if (currentSection) {
// Ensure the current section is initialized.
if (!config[currentSection]) {
config[currentSection] = {};
}
config[currentSection][trimmedKey] = value;
}
}
}
});

return config;
}

function getEditorConfig(filePath: string): any {
let combinedConfig: any = {};
let globalConfig: any = {};
let currentDir: string = path.dirname(filePath);
const rootDir: string = path.parse(currentDir).root;

// Traverse from the file's directory to the root directory.
for (;;) {
const editorConfigPath: string = path.join(currentDir, '.editorconfig');
if (fs.existsSync(editorConfigPath)) {
const configFileContent: string = fs.readFileSync(editorConfigPath, 'utf-8');
const configData = parseEditorConfigContent(configFileContent);

// Extract global (sectionless) entries.
if (configData['*']) {
globalConfig = {
...globalConfig,
...configData['*']
};
}

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

// Check if the current .editorconfig is the root.
if (configData['*']?.root?.toLowerCase() === 'true') {
break; // Stop searching after processing the root = true file.
}
}
if (currentDir === rootDir) {
break; // Stop the loop after checking the root directory.
}
currentDir = path.dirname(currentDir);
}

// Merge global config with section-based config.
return {
...globalConfig,
...combinedConfig
};
}

// Look up the appropriate .editorconfig settings for the specified file.
// This is intentionally not async to avoid races due to multiple entrancy.
export function getEditorConfigSettings(fsPath: string): Promise<any> {
let editorConfigSettings: any = cachedEditorConfigSettings.get(fsPath);
if (!editorConfigSettings) {
editorConfigSettings = getEditorConfig(fsPath);
cachedEditorConfigSettings.set(fsPath, editorConfigSettings);
}
return editorConfigSettings;
}
67 changes: 2 additions & 65 deletions Extension/src/LanguageServer/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
'use strict';

import { execSync } from 'child_process';
import * as editorConfig from 'editorconfig';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
Expand All @@ -17,7 +16,8 @@ import * as which from 'which';
import { getCachedClangFormatPath, getCachedClangTidyPath, getExtensionFilePath, getRawSetting, isArray, isArrayOfString, isBoolean, isNumber, isObject, isString, isValidMapping, setCachedClangFormatPath, setCachedClangTidyPath } from '../common';
import { isWindows } from '../constants';
import * as telemetry from '../telemetry';
import { DefaultClient, cachedEditorConfigLookups, cachedEditorConfigSettings, hasTrustedCompilerPaths } from './client';
import { cachedEditorConfigLookups, DefaultClient, hasTrustedCompilerPaths } from './client';
import { getEditorConfigSettings, mapIndentationReferenceToEditorConfig, mapIndentToEditorConfig, mapNewOrSameLineToEditorConfig, mapWrapToEditorConfig } from './editorConfig';
import { clients } from './extension';
import { CommentPattern } from './languageConfig';
import { PersistentState } from './persistentState';
Expand Down Expand Up @@ -1076,66 +1076,3 @@ export class OtherSettings {
public get searchExclude(): Excludes { return this.getAsExcludes("search", "exclude", this.defaultSearchExcludes, this.resource); }
public get workbenchSettingsEditor(): string { return this.getAsString("workbench.settings", "editor", this.resource, "ui"); }
}

function mapIndentationReferenceToEditorConfig(value: string | undefined): string {
if (value !== undefined) {
// Will never actually be undefined, as these settings have default values.
if (value === "statementBegin") {
return "statement_begin";
}
if (value === "outermostParenthesis") {
return "outermost_parenthesis";
}
}
return "innermost_parenthesis";
}

function mapIndentToEditorConfig(value: string | undefined): string {
if (value !== undefined) {
// Will never actually be undefined, as these settings have default values.
if (value === "leftmostColumn") {
return "leftmost_column";
}
if (value === "oneLeft") {
return "one_left";
}
}
return "none";
}

function mapNewOrSameLineToEditorConfig(value: string | undefined): string {
if (value !== undefined) {
// Will never actually be undefined, as these settings have default values.
if (value === "newLine") {
return "new_line";
}
if (value === "sameLine") {
return "same_line";
}
}
return "ignore";
}

function mapWrapToEditorConfig(value: string | undefined): string {
if (value !== undefined) {
// Will never actually be undefined, as these settings have default values.
if (value === "allOneLineScopes") {
return "all_one_line_scopes";
}
if (value === "oneLiners") {
return "one_liners";
}
}
return "never";
}

// Look up the appropriate .editorconfig settings for the specified file.
// This is intentionally not async to avoid races due to multiple entrancy.
export function getEditorConfigSettings(fsPath: string): Promise<any> {
let editorConfigSettings: any = cachedEditorConfigSettings.get(fsPath);
if (!editorConfigSettings) {
editorConfigSettings = editorConfig.parseSync(fsPath);
cachedEditorConfigSettings.set(fsPath, editorConfigSettings);
}
return editorConfigSettings;
}
11 changes: 0 additions & 11 deletions Extension/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
'use strict';

const path = require('path');
const copyPlugin = require('copy-webpack-plugin');

/**@type {import('webpack').Configuration}*/
const config = {
Expand All @@ -32,16 +31,6 @@ const config = {
extensions: ['.js', '.ts',],
mainFields: ['main', 'module'],
},
plugins: [
new copyPlugin({
patterns: [
{
from: path.resolve(__dirname, 'node_modules', "@one-ini", "wasm", "one_ini_bg.wasm"),
to: path.resolve(__dirname, 'dist', 'src')
}
]
})
],
module: {
rules: [{
test: /\.ts$/,
Expand Down
Loading