in src/vs/workbench/services/preferences/common/preferencesModels.ts [259:426]
function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, previousParents: string[]) => boolean): ISettingsGroup[] {
const settings: ISetting[] = [];
let overrideSetting: ISetting | null = null;
let currentProperty: string | null = null;
let currentParent: any = [];
const previousParents: any[] = [];
let settingsPropertyIndex: number = -1;
const range = {
startLineNumber: 0,
startColumn: 0,
endLineNumber: 0,
endColumn: 0
};
function onValue(value: any, offset: number, length: number) {
if (Array.isArray(currentParent)) {
(<any[]>currentParent).push(value);
} else if (currentProperty) {
currentParent[currentProperty] = value;
}
if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) {
// settings value started
const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting!.overrides![overrideSetting!.overrides!.length - 1];
if (setting) {
const valueStartPosition = model.getPositionAt(offset);
const valueEndPosition = model.getPositionAt(offset + length);
setting.value = value;
setting.valueRange = {
startLineNumber: valueStartPosition.lineNumber,
startColumn: valueStartPosition.column,
endLineNumber: valueEndPosition.lineNumber,
endColumn: valueEndPosition.column
};
setting.range = assign(setting.range, {
endLineNumber: valueEndPosition.lineNumber,
endColumn: valueEndPosition.column
});
}
}
}
const visitor: JSONVisitor = {
onObjectBegin: (offset: number, length: number) => {
if (isSettingsProperty(currentProperty!, previousParents)) {
// Settings started
settingsPropertyIndex = previousParents.length;
const position = model.getPositionAt(offset);
range.startLineNumber = position.lineNumber;
range.startColumn = position.column;
}
const object = {};
onValue(object, offset, length);
currentParent = object;
currentProperty = null;
previousParents.push(currentParent);
},
onObjectProperty: (name: string, offset: number, length: number) => {
currentProperty = name;
if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) {
// setting started
const settingStartPosition = model.getPositionAt(offset);
const setting: ISetting = {
description: [],
descriptionIsMarkdown: false,
key: name,
keyRange: {
startLineNumber: settingStartPosition.lineNumber,
startColumn: settingStartPosition.column + 1,
endLineNumber: settingStartPosition.lineNumber,
endColumn: settingStartPosition.column + length
},
range: {
startLineNumber: settingStartPosition.lineNumber,
startColumn: settingStartPosition.column,
endLineNumber: 0,
endColumn: 0
},
value: null,
valueRange: nullRange,
descriptionRanges: [],
overrides: [],
overrideOf: withNullAsUndefined(overrideSetting)
};
if (previousParents.length === settingsPropertyIndex + 1) {
settings.push(setting);
if (OVERRIDE_PROPERTY_PATTERN.test(name)) {
overrideSetting = setting;
}
} else {
overrideSetting!.overrides!.push(setting);
}
}
},
onObjectEnd: (offset: number, length: number) => {
currentParent = previousParents.pop();
if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) {
// setting ended
const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting!.overrides![overrideSetting!.overrides!.length - 1];
if (setting) {
const valueEndPosition = model.getPositionAt(offset + length);
setting.valueRange = assign(setting.valueRange, {
endLineNumber: valueEndPosition.lineNumber,
endColumn: valueEndPosition.column
});
setting.range = assign(setting.range, {
endLineNumber: valueEndPosition.lineNumber,
endColumn: valueEndPosition.column
});
}
if (previousParents.length === settingsPropertyIndex + 1) {
overrideSetting = null;
}
}
if (previousParents.length === settingsPropertyIndex) {
// settings ended
const position = model.getPositionAt(offset);
range.endLineNumber = position.lineNumber;
range.endColumn = position.column;
}
},
onArrayBegin: (offset: number, length: number) => {
const array: any[] = [];
onValue(array, offset, length);
previousParents.push(currentParent);
currentParent = array;
currentProperty = null;
},
onArrayEnd: (offset: number, length: number) => {
currentParent = previousParents.pop();
if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) {
// setting value ended
const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting!.overrides![overrideSetting!.overrides!.length - 1];
if (setting) {
const valueEndPosition = model.getPositionAt(offset + length);
setting.valueRange = assign(setting.valueRange, {
endLineNumber: valueEndPosition.lineNumber,
endColumn: valueEndPosition.column
});
setting.range = assign(setting.range, {
endLineNumber: valueEndPosition.lineNumber,
endColumn: valueEndPosition.column
});
}
}
},
onLiteralValue: onValue,
onError: (error) => {
const setting = settings[settings.length - 1];
if (setting && (isNullRange(setting.range) || isNullRange(setting.keyRange) || isNullRange(setting.valueRange))) {
settings.pop();
}
}
};
if (!model.isDisposed()) {
visit(model.getValue(), visitor);
}
return settings.length > 0 ? [<ISettingsGroup>{
sections: [
{
settings
}
],
title: '',
titleRange: nullRange,
range
}] : [];
}