Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/git/common/utils.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import type * as vscode from 'vscode';
7
import { Remote } from '../vscode/git';
8
9
interface GitConfigSection {
10
name: string;
11
subSectionName?: string;
12
properties: { [key: string]: string };
13
}
14
15
class GitConfigParser {
16
private static readonly _lineSeparator = /\r?\n/;
17
18
private static readonly _propertyRegex = /^\s*(\w+)\s*=\s*"?([^"]+)"?$/;
19
private static readonly _sectionRegex = /^\s*\[\s*([^\]]+?)\s*(\"[^"]+\")*\]\s*$/;
20
21
static parse(raw: string): GitConfigSection[] {
22
const config: { sections: GitConfigSection[] } = { sections: [] };
23
let section: GitConfigSection = { name: 'DEFAULT', properties: {} };
24
25
const addSection = (section?: GitConfigSection) => {
26
if (!section) { return; }
27
config.sections.push(section);
28
};
29
30
for (const line of raw.split(GitConfigParser._lineSeparator)) {
31
// Section
32
const sectionMatch = line.match(GitConfigParser._sectionRegex);
33
if (sectionMatch?.length === 3) {
34
addSection(section);
35
section = { name: sectionMatch[1], subSectionName: sectionMatch[2]?.replaceAll('"', ''), properties: {} };
36
37
continue;
38
}
39
40
// Property
41
const propertyMatch = line.match(GitConfigParser._propertyRegex);
42
if (propertyMatch?.length === 3 && !Object.keys(section.properties).includes(propertyMatch[1])) {
43
section.properties[propertyMatch[1]] = propertyMatch[2];
44
}
45
}
46
47
addSection(section);
48
49
return config.sections;
50
}
51
}
52
53
export function parseGitRemotes(raw: string): Remote[] {
54
const remotes: Remote[] = [];
55
56
for (const remoteSection of GitConfigParser.parse(raw).filter(s => s.name === 'remote')) {
57
if (remoteSection.subSectionName) {
58
remotes.push({
59
name: remoteSection.subSectionName,
60
fetchUrl: remoteSection.properties['url'],
61
pushUrl: remoteSection.properties['pushurl'] ?? remoteSection.properties['url'],
62
isReadOnly: false
63
});
64
}
65
}
66
67
return remotes;
68
}
69
70
export interface GitUriParams {
71
path: string;
72
ref: string;
73
submoduleOf?: string;
74
}
75
76
export interface GitUriOptions {
77
scheme?: string;
78
replaceFileExtension?: boolean;
79
submoduleOf?: string;
80
}
81
82
// As a mitigation for extensions like ESLint showing warnings and errors
83
// for git URIs, let's change the file extension of these uris to .git,
84
// when `replaceFileExtension` is true.
85
export function toGitUri(uri: vscode.Uri, ref: string, options: GitUriOptions = {}): vscode.Uri {
86
const params: GitUriParams = {
87
path: uri.fsPath,
88
ref
89
};
90
91
if (options.submoduleOf) {
92
params.submoduleOf = options.submoduleOf;
93
}
94
95
let path = uri.path;
96
97
if (options.replaceFileExtension) {
98
path = `${path}.git`;
99
} else if (options.submoduleOf) {
100
path = `${path}.diff`;
101
}
102
103
return uri.with({ scheme: options.scheme ?? 'git', path, query: JSON.stringify(params) });
104
}
105
106