Skip to content

Commit a4f6ba1

Browse files
committed
[release] prepare v0.20.0 release (2)
6c7bfb3 src/debugAdapter: report that next is automatically cancelled if interrupted f38e348 src/goLanguageServer: propagate go.buildFlags,buildTags to gopls dbc8da9 src/goDebug: fix drive casing when substituting paths 2f72921 test/integration/goDebug: disable a substitutePath test that times out Change-Id: I1f808808aca0160ad51f1b8a0f809365d3f8513d
2 parents dfc4e72 + 6c7bfb3 commit a4f6ba1

File tree

9 files changed

+457
-64
lines changed

9 files changed

+457
-64
lines changed

docs/settings.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Default: `false`
7979

8080
### `go.buildFlags`
8181

82-
Flags to `go build`/`go test` used during build-on-save or running tests. (e.g. ["-ldflags='-s'"])
82+
Flags to `go build`/`go test` used during build-on-save or running tests. (e.g. ["-ldflags='-s'"]) This is propagated to the language server if `gopls.buildFlags` is not specified.
8383

8484
### `go.buildOnSave`
8585

@@ -91,7 +91,7 @@ Default: `package`
9191

9292
### `go.buildTags`
9393

94-
The Go build tags to use for all commands, that support a `-tags '...'` argument. When running tests, go.testTags will be used instead if it was set.
94+
The Go build tags to use for all commands, that support a `-tags '...'` argument. When running tests, go.testTags will be used instead if it was set. This is propagated to the language server if `gopls.buildFlags` is not specified.
9595

9696
Default: ``
9797

@@ -617,6 +617,8 @@ buildFlags is the set of flags passed on to the build system when invoked.
617617
It is applied to queries like `go list`, which is used when discovering files.
618618
The most common use is to set `-tags`.
619619

620+
If unspecified, values of `go.buildFlags, go.buildTags` will be propagated.
621+
620622

621623
#### `codelenses`
622624
codelenses overrides the enabled/disabled state of code lenses. See the "Code Lenses"
@@ -626,7 +628,7 @@ Example Usage:
626628
```json5
627629
"gopls": {
628630
...
629-
"codelenses": {
631+
"codelens": {
630632
"generate": false, // Don't show the `go generate` lens.
631633
"gc_details": true // Show a code lens toggling the display of gc's choices.
632634
}

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -847,13 +847,13 @@
847847
"type": "string"
848848
},
849849
"default": [],
850-
"description": "Flags to `go build`/`go test` used during build-on-save or running tests. (e.g. [\"-ldflags='-s'\"])",
850+
"description": "Flags to `go build`/`go test` used during build-on-save or running tests. (e.g. [\"-ldflags='-s'\"]) This is propagated to the language server if `gopls.buildFlags` is not specified.",
851851
"scope": "resource"
852852
},
853853
"go.buildTags": {
854854
"type": "string",
855855
"default": "",
856-
"description": "The Go build tags to use for all commands, that support a `-tags '...'` argument. When running tests, go.testTags will be used instead if it was set.",
856+
"description": "The Go build tags to use for all commands, that support a `-tags '...'` argument. When running tests, go.testTags will be used instead if it was set. This is propagated to the language server if `gopls.buildFlags` is not specified.",
857857
"scope": "resource"
858858
},
859859
"go.testTags": {
@@ -1693,7 +1693,7 @@
16931693
"properties": {
16941694
"buildFlags": {
16951695
"type": "array",
1696-
"markdownDescription": "buildFlags is the set of flags passed on to the build system when invoked.\nIt is applied to queries like `go list`, which is used when discovering files.\nThe most common use is to set `-tags`.\n",
1696+
"markdownDescription": "buildFlags is the set of flags passed on to the build system when invoked.\nIt is applied to queries like `go list`, which is used when discovering files.\nThe most common use is to set `-tags`.\n\nIf unspecified, values of `go.buildFlags, go.buildTags` will be propagated.\n",
16971697
"default": [],
16981698
"scope": "resource"
16991699
},
@@ -1755,7 +1755,7 @@
17551755
},
17561756
"codelenses": {
17571757
"type": "object",
1758-
"markdownDescription": "codelenses overrides the enabled/disabled state of code lenses. See the \"Code Lenses\"\nsection of settings.md for the list of supported lenses.\n\nExample Usage:\n```json5\n\"gopls\": {\n...\n \"codelenses\": {\n \"generate\": false, // Don't show the `go generate` lens.\n \"gc_details\": true // Show a code lens toggling the display of gc's choices.\n }\n...\n}\n```\n",
1758+
"markdownDescription": "codelenses overrides the enabled/disabled state of code lenses. See the \"Code Lenses\"\nsection of settings.md for the list of supported lenses.\n\nExample Usage:\n```json5\n\"gopls\": {\n...\n \"codelens\": {\n \"generate\": false, // Don't show the `go generate` lens.\n \"gc_details\": true // Show a code lens toggling the display of gc's choices.\n }\n...\n}\n```\n",
17591759
"default": {
17601760
"gc_details": false,
17611761
"generate": true,

src/debugAdapter/goDebug.ts

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ interface DebuggerState {
9090
currentGoroutine: DebugGoroutine;
9191
Running: boolean;
9292
Threads: DebugThread[];
93+
NextInProgress: boolean;
9394
}
9495

9596
export interface PackageBuildInfo {
@@ -371,7 +372,18 @@ function normalizePath(filePath: string) {
371372
return filePath;
372373
}
373374

374-
function normalizeSeparators(filePath: string): string {
375+
// normalizeSeparators will prepare the filepath for comparison in mapping from
376+
// local to debugger path and from debugger path to local path. All separators are
377+
// replaced with '/', and the drive name is capitalized for windows paths.
378+
// Exported for testing
379+
export function normalizeSeparators(filePath: string): string {
380+
// Although the current machine may not be running windows,
381+
// the remote machine may be and we need to fix the drive
382+
// casing.
383+
// This is a workaround for issue in https://github.com/Microsoft/vscode/issues/9448#issuecomment-244804026
384+
if (filePath.indexOf(':') === 1) {
385+
filePath = filePath.substr(0, 1).toUpperCase() + filePath.substr(1);
386+
}
375387
return filePath.replace(/\/|\\/g, '/');
376388
}
377389

@@ -846,6 +858,7 @@ export class GoDebugSession extends LoggingDebugSession {
846858
private breakpoints: Map<string, DebugBreakpoint[]>;
847859
// Editing breakpoints requires halting delve, skip sending Stop Event to VS Code in such cases
848860
private skipStopEventOnce: boolean;
861+
private overrideStopReason: string;
849862
private debugState: DebuggerState;
850863
private delve: Delve;
851864
private localPathSeparator: string;
@@ -866,13 +879,16 @@ export class GoDebugSession extends LoggingDebugSession {
866879

867880
private continueEpoch = 0;
868881
private continueRequestRunning = false;
882+
private nextEpoch = 0;
883+
private nextRequestRunning = false;
869884
public constructor(
870885
debuggerLinesStartAt1: boolean,
871886
isServer: boolean = false,
872887
readonly fileSystem = fs) {
873888
super('', debuggerLinesStartAt1, isServer);
874889
this.variableHandles = new Handles<DebugVariable>();
875890
this.skipStopEventOnce = false;
891+
this.overrideStopReason = '';
876892
this.stopOnEntry = false;
877893
this.debugState = null;
878894
this.delve = null;
@@ -1292,11 +1308,25 @@ export class GoDebugSession extends LoggingDebugSession {
12921308
log('Debuggee is not running. Setting breakpoints without halting.');
12931309
await this.setBreakPoints(response, args);
12941310
} else {
1311+
// Skip stop event if a continue request is running.
12951312
this.skipStopEventOnce = this.continueRequestRunning;
1313+
const haltedDuringNext = this.nextRequestRunning;
1314+
if (haltedDuringNext) {
1315+
this.overrideStopReason = 'next cancelled';
1316+
}
1317+
12961318
log(`Halting before setting breakpoints. SkipStopEventOnce is ${this.skipStopEventOnce}.`);
12971319
this.delve.callPromise('Command', [{ name: 'halt' }]).then(
12981320
() => {
12991321
return this.setBreakPoints(response, args).then(() => {
1322+
// We do not want to continue if it was running a next request, since the
1323+
// request was automatically cancelled.
1324+
if (haltedDuringNext) {
1325+
// Send an output event containing a warning that next was cancelled.
1326+
const warning = `Setting breakpoints during 'next', 'step in' or 'step out' halted delve and cancelled the next request`;
1327+
this.sendEvent(new OutputEvent(warning, 'stderr'));
1328+
return;
1329+
}
13001330
return this.continue(true).then(null, (err) => {
13011331
this.logDelveError(err, 'Failed to continue delve after halting it to set breakpoints');
13021332
});
@@ -1676,8 +1706,16 @@ export class GoDebugSession extends LoggingDebugSession {
16761706
}
16771707

16781708
protected nextRequest(response: DebugProtocol.NextResponse): void {
1709+
this.nextEpoch++;
1710+
const closureEpoch = this.nextEpoch;
1711+
this.nextRequestRunning = true;
1712+
16791713
log('NextRequest');
16801714
this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'next' }], (err, out) => {
1715+
if (closureEpoch === this.continueEpoch) {
1716+
this.nextRequestRunning = false;
1717+
}
1718+
16811719
if (err) {
16821720
this.logDelveError(err, 'Failed to next');
16831721
}
@@ -1691,8 +1729,16 @@ export class GoDebugSession extends LoggingDebugSession {
16911729
}
16921730

16931731
protected stepInRequest(response: DebugProtocol.StepInResponse): void {
1732+
this.nextEpoch++;
1733+
const closureEpoch = this.nextEpoch;
1734+
this.nextRequestRunning = true;
1735+
16941736
log('StepInRequest');
16951737
this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'step' }], (err, out) => {
1738+
if (closureEpoch === this.continueEpoch) {
1739+
this.nextRequestRunning = false;
1740+
}
1741+
16961742
if (err) {
16971743
this.logDelveError(err, 'Failed to step in');
16981744
}
@@ -1706,8 +1752,16 @@ export class GoDebugSession extends LoggingDebugSession {
17061752
}
17071753

17081754
protected stepOutRequest(response: DebugProtocol.StepOutResponse): void {
1755+
this.nextEpoch++;
1756+
const closureEpoch = this.nextEpoch;
1757+
this.nextRequestRunning = true;
1758+
17091759
log('StepOutRequest');
17101760
this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'stepOut' }], (err, out) => {
1761+
if (closureEpoch === this.continueEpoch) {
1762+
this.nextRequestRunning = false;
1763+
}
1764+
17111765
if (err) {
17121766
this.logDelveError(err, 'Failed to step out');
17131767
}
@@ -2341,6 +2395,11 @@ export class GoDebugSession extends LoggingDebugSession {
23412395
return;
23422396
}
23432397

2398+
if (this.overrideStopReason?.length > 0) {
2399+
reason = this.overrideStopReason;
2400+
this.overrideStopReason = '';
2401+
}
2402+
23442403
const stoppedEvent = new StoppedEvent(reason, this.debugState.currentGoroutine.id);
23452404
(<any>stoppedEvent.body).allThreadsStopped = true;
23462405
this.sendEvent(stoppedEvent);
@@ -2364,7 +2423,7 @@ export class GoDebugSession extends LoggingDebugSession {
23642423
} catch (error) {
23652424
this.logDelveError(error, 'Failed to get state');
23662425
// Fall back to the internal tracking.
2367-
return this.continueRequestRunning;
2426+
return this.continueRequestRunning || this.nextRequestRunning;
23682427
}
23692428
}
23702429

src/goLanguageServer.ts

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,7 @@ function buildLanguageClientOption(cfg: LanguageServerConfig): BuildLanguageClie
290290
// buildLanguageClient returns a language client built using the given language server config.
291291
// The returned language client need to be started before use.
292292
export async function buildLanguageClient(cfg: BuildLanguageClientOption): Promise<LanguageClient> {
293-
let goplsWorkspaceConfig = getGoplsConfig() as any;
294-
goplsWorkspaceConfig = filterDefaultConfigValues(goplsWorkspaceConfig, 'gopls', undefined);
295-
goplsWorkspaceConfig = await adjustGoplsWorkspaceConfiguration(cfg, goplsWorkspaceConfig);
293+
const goplsWorkspaceConfig = await adjustGoplsWorkspaceConfiguration(cfg, getGoplsConfig(), 'gopls', undefined);
296294
const c = new LanguageClient(
297295
'go', // id
298296
cfg.serverName, // name e.g. gopls
@@ -505,8 +503,7 @@ export async function buildLanguageClient(cfg: BuildLanguageClientOption): Promi
505503
const scopeUri = params.items[i].scopeUri;
506504
const resource = scopeUri ? vscode.Uri.parse(scopeUri) : undefined;
507505
const section = params.items[i].section;
508-
workspaceConfig = filterDefaultConfigValues(workspaceConfig, section, resource);
509-
workspaceConfig = await adjustGoplsWorkspaceConfiguration(cfg, workspaceConfig);
506+
workspaceConfig = await adjustGoplsWorkspaceConfiguration(cfg, workspaceConfig, section, resource);
510507
}
511508
ret.push(workspaceConfig);
512509
}
@@ -519,19 +516,15 @@ export async function buildLanguageClient(cfg: BuildLanguageClientOption): Promi
519516
return c;
520517
}
521518

522-
// filterDefaultConfigValues removes the entries filled based on the default values
519+
// filterGoplsDefaultConfigValues removes the entries filled based on the default values
523520
// and selects only those the user explicitly specifies in their settings.
524-
// This assumes workspaceConfig is a non-null(undefined) object type.
521+
// This returns a new object created based on the filtered properties of workspaceConfig.
525522
// Exported for testing.
526-
export function filterDefaultConfigValues(workspaceConfig: any, section: string, resource: vscode.Uri): any {
523+
export function filterGoplsDefaultConfigValues(workspaceConfig: any, resource: vscode.Uri): any {
527524
if (!workspaceConfig) {
528-
return workspaceConfig;
525+
workspaceConfig = {};
529526
}
530-
531-
const dot = section?.lastIndexOf('.') || -1;
532-
const sectionKey = dot >= 0 ? section.substr(0, dot) : section; // e.g. 'gopls'
533-
534-
const cfg = vscode.workspace.getConfiguration(sectionKey, resource);
527+
const cfg = getGoplsConfig(resource);
535528
const filtered = {} as { [key: string]: any };
536529
for (const [key, value] of Object.entries(workspaceConfig)) {
537530
if (typeof value === 'function') {
@@ -556,31 +549,63 @@ export function filterDefaultConfigValues(workspaceConfig: any, section: string,
556549
return filtered;
557550
}
558551

559-
// adjustGoplsWorkspaceConfiguration adds any extra options to the gopls
560-
// config. Right now, the only extra option is enabling experiments for the
561-
// Nightly extension.
562-
async function adjustGoplsWorkspaceConfiguration(cfg: LanguageServerConfig, config: any): Promise<any> {
563-
if (!config) {
564-
return config;
552+
// passGoConfigToGoplsConfigValues passes some of the relevant 'go.' settings to gopls settings.
553+
// This assumes `goplsWorkspaceConfig` is an output of filterGoplsDefaultConfigValues,
554+
// so it is modifiable and doesn't contain properties that are not explicitly set.
555+
// - go.buildTags and go.buildFlags are passed as gopls.buildFlags
556+
// if goplsWorkspaceConfig doesn't explicitly set it yet.
557+
// Exported for testing.
558+
export function passGoConfigToGoplsConfigValues(goplsWorkspaceConfig: any, goWorkspaceConfig: any): any {
559+
if (!goplsWorkspaceConfig) {
560+
goplsWorkspaceConfig = {};
561+
}
562+
563+
// If gopls.buildFlags is set, don't touch it.
564+
if (goplsWorkspaceConfig.buildFlags === undefined) {
565+
const buildFlags = [] as string[];
566+
if (goWorkspaceConfig?.buildFlags) {
567+
buildFlags.push(...goWorkspaceConfig?.buildFlags);
568+
}
569+
if (goWorkspaceConfig?.buildTags && buildFlags.indexOf('-tags') === -1) {
570+
buildFlags.push('-tags', goWorkspaceConfig?.buildTags);
571+
}
572+
if (buildFlags.length > 0) {
573+
goplsWorkspaceConfig.buildFlags = buildFlags;
574+
}
565575
}
576+
return goplsWorkspaceConfig;
577+
}
578+
579+
// adjustGoplsWorkspaceConfiguration filters unnecessary options and adds any necessary, additional
580+
// options to the gopls config. See filterGoplsDefaultConfigValues, passGoConfigToGoplsConfigValues.
581+
// If this is for the nightly extension, we also request to activate features under experiments.
582+
async function adjustGoplsWorkspaceConfiguration(cfg: LanguageServerConfig, workspaceConfig: any, section: string, resource: vscode.Uri): Promise<any> {
583+
// We process only gopls config
584+
if (section !== 'gopls') {
585+
return workspaceConfig;
586+
}
587+
588+
workspaceConfig = filterGoplsDefaultConfigValues(workspaceConfig, resource);
589+
// note: workspaceConfig is a modifiable, valid object.
590+
workspaceConfig = passGoConfigToGoplsConfigValues(workspaceConfig, getGoConfig(resource));
591+
566592
// Only modify the user's configurations for the Nightly.
567593
if (extensionId !== 'golang.go-nightly') {
568-
return config;
594+
return workspaceConfig;
569595
}
570596
// allExperiments is only available with gopls/v0.5.2 and above.
571597
const version = await getLocalGoplsVersion(cfg);
572598
if (!version) {
573-
return config;
599+
return workspaceConfig;
574600
}
575601
const sv = semver.parse(version, true);
576602
if (!sv || semver.lt(sv, 'v0.5.2')) {
577-
return config;
603+
return workspaceConfig;
578604
}
579-
const newConfig = Object.assign({}, config);
580-
if (!config['allExperiments']) {
581-
newConfig['allExperiments'] = true;
605+
if (!workspaceConfig['allExperiments']) {
606+
workspaceConfig['allExperiments'] = true;
582607
}
583-
return newConfig;
608+
return workspaceConfig;
584609
}
585610

586611
// createTestCodeLens adds the go.test.cursor and go.debug.cursor code lens

src/util.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,12 @@ let toolsGopath: string;
158158

159159
// getGoConfig is declared as an exported const rather than a function, so it can be stubbbed in testing.
160160
export const getGoConfig = (uri?: vscode.Uri) => {
161-
return getConfig('go');
161+
return getConfig('go', uri);
162162
};
163163

164164
// getGoplsConfig returns the user's gopls configuration.
165-
export function getGoplsConfig() {
166-
return getConfig('gopls');
165+
export function getGoplsConfig(uri?: vscode.Uri) {
166+
return getConfig('gopls', uri);
167167
}
168168

169169
// getCheckForToolsUpdatesConfig returns go.toolsManagement.checkForUpdates configuration.

0 commit comments

Comments
 (0)