Skip to content

Commit faef822

Browse files
authored
Fix logging and configuration watching in LSP (#750)
* Log LSP messages * Log via LSP once we're connected * Don't log time twice now that time is added on the frontend side * Add `justfile` for CLI shortcuts * Finish plumbing configuration change notifications * Make log level a quarto setting * Take info, warn, and error log levels * Add `log()` wrappers * Pass `logLevel` via init options * Pass log level to client * Ignore format commit in git blame * Fix default setting * Revert propagation of log level to client * Rename `LogFunctionLogger` to `Logger` * Add comment about default `console.log` handling * Actually pass init option to logger * Remove justfile * Remove redundant config watching
1 parent c800f78 commit faef822

File tree

19 files changed

+322
-153
lines changed

19 files changed

+322
-153
lines changed

.git-blame-ignore-revs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This file lists revisions of large-scale formatting/style changes so that
2+
# they can be excluded from git blame results.
3+
#
4+
# To set this file as the default ignore file for git blame, run:
5+
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
6+
7+
# Format vscode extention and LSP files consistently (#748)
8+
a1513effc913e6e59651256d79295da37134dbbf

apps/lsp/.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
module.exports = {
22
root: true,
33
extends: ["custom-server"],
4+
rules: {
5+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
6+
},
47
};

apps/lsp/src/config.ts

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ import {
2424
IncludeWorkspaceHeaderCompletions,
2525
LsConfiguration,
2626
defaultLsConfiguration,
27-
PreferredMdPathExtensionStyle
27+
PreferredMdPathExtensionStyle,
28+
ILogger,
29+
LogLevel
2830
} from './service';
31+
import { Logger } from './logging';
2932

3033
export type ValidateEnabled = 'ignore' | 'warning' | 'error' | 'hint';
3134

@@ -34,17 +37,14 @@ export interface Settings {
3437
readonly colorTheme: string;
3538
};
3639
readonly quarto: {
40+
readonly logLevel: LogLevel;
3741
readonly path: string;
3842
readonly mathjax: {
3943
readonly scale: number;
4044
readonly extensions: MathjaxSupportedExtension[];
4145
}
4246
};
4347
readonly markdown: {
44-
readonly server: {
45-
readonly log: 'off' | 'debug' | 'trace';
46-
};
47-
4848
readonly preferredMdPathExtensionStyle: 'auto' | 'includeExtension' | 'removeExtension';
4949

5050
readonly suggest: {
@@ -83,16 +83,14 @@ function defaultSettings(): Settings {
8383
colorTheme: 'Dark+'
8484
},
8585
quarto: {
86+
logLevel: LogLevel.Warn,
8687
path: "",
8788
mathjax: {
8889
scale: 1,
8990
extensions: []
9091
}
9192
},
9293
markdown: {
93-
server: {
94-
log: 'off'
95-
},
9694
preferredMdPathExtensionStyle: 'auto',
9795
suggest: {
9896
paths: {
@@ -131,13 +129,29 @@ export class ConfigurationManager extends Disposable {
131129
public readonly onDidChangeConfiguration = this._onDidChangeConfiguration.event;
132130

133131
private _settings: Settings;
132+
private _logger: ILogger;
134133

135-
constructor(private readonly connection_: Connection) {
134+
constructor(
135+
private readonly connection_: Connection,
136+
logger: ILogger,
137+
) {
136138
super();
139+
this._logger = logger;
137140
this._settings = defaultSettings();
138141
}
139142

143+
public init(logLevel: LogLevel) {
144+
this._settings = {
145+
...this._settings,
146+
quarto: {
147+
...this._settings.quarto,
148+
logLevel,
149+
}
150+
};
151+
}
152+
140153
public async update() {
154+
this._logger.logTrace('Sending \'configuration\' request');
141155
const settings = await this.connection_.workspace.getConfiguration();
142156

143157
this._settings = {
@@ -146,6 +160,7 @@ export class ConfigurationManager extends Disposable {
146160
colorTheme: settings.workbench.colorTheme
147161
},
148162
quarto: {
163+
logLevel: Logger.parseLogLevel(settings.quarto.server.logLevel),
149164
path: settings.quarto.path,
150165
mathjax: {
151166
scale: settings.quarto.mathjax.scale,
@@ -157,14 +172,22 @@ export class ConfigurationManager extends Disposable {
157172
}
158173

159174
public async subscribe() {
160-
await this.update();
175+
// Ignore the settings in parameters, the modern usage is to fetch the
176+
// settings when we get this notification. This causes the client to send
177+
// any updates for settings under the `quarto` section.
178+
this.connection_.onDidChangeConfiguration((_params) => {
179+
this._logger.logNotification('didChangeConfiguration');
180+
this.update();
181+
});
182+
183+
// Get notified of configuration changes by client
161184
await this.connection_.client.register(
162185
DidChangeConfigurationNotification.type,
163186
undefined
164187
);
165-
this.connection_.onDidChangeConfiguration(() => {
166-
this.update();
167-
});
188+
189+
// Retrieve initial values for settings of interest
190+
await this.update();
168191
}
169192

170193
public getSettings(): Settings {

apps/lsp/src/diagnostics.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import {
3535
ILogger,
3636
IMdLanguageService,
3737
IWorkspace,
38-
LogLevel,
3938
} from "./service";
4039
import {
4140
ConfigurationManager,
@@ -130,7 +129,7 @@ export async function registerDiagnostics(
130129
FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport
131130
> => {
132131

133-
logger.log(LogLevel.Debug, "connection.languages.diagnostics.on", {
132+
logger.logDebug("connection.languages.diagnostics.on", {
134133
document: params.textDocument.uri,
135134
});
136135

apps/lsp/src/index.ts

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import { registerCustomMethods } from "./custom";
4040
import { isWindows, LspConnection } from "core-node";
4141
import { initQuartoContext, Document, markdownitParser, LspInitializationOptions } from "quarto-core";
4242
import { ConfigurationManager, lsConfiguration } from "./config";
43-
import { LogFunctionLogger } from "./logging";
43+
import { Logger } from "./logging";
4444
import { languageServiceWorkspace } from "./workspace";
4545
import { middlewareCapabilities, middlewareRegister } from "./middleware";
4646
import { createLanguageService, IMdLanguageService } from "./service";
@@ -52,12 +52,15 @@ import { registerDiagnostics } from "./diagnostics";
5252
// Also include all preview / proposed LSP features.
5353
const connection = createConnection(ProposedFeatures.all);
5454

55+
// Initialize logger
56+
const logger = new Logger(console.log.bind(console));
57+
5558
// Create text document manager
5659
const documents: TextDocuments<Document> = new TextDocuments(TextDocument);
5760
documents.listen(connection);
5861

5962
// Configuration
60-
const configManager = new ConfigurationManager(connection);
63+
const configManager = new ConfigurationManager(connection, logger);
6164
const config = lsConfiguration(configManager);
6265

6366
// Capabilities
@@ -66,16 +69,29 @@ let capabilities: ClientCapabilities | undefined;
6669
// Initialization options
6770
let initializationOptions: LspInitializationOptions | undefined;
6871

69-
// Markdowdn language service
72+
// Markdown language service
7073
let mdLs: IMdLanguageService | undefined;
7174

7275
connection.onInitialize((params: InitializeParams) => {
76+
// Set log level from initialization options if provided so that we use the
77+
// expected level as soon as possible
78+
const initLogLevel = Logger.parseLogLevel(
79+
params.initializationOptions?.logLevel ?? "warn"
80+
);
81+
logger.init(initLogLevel);
82+
configManager.init(initLogLevel);
83+
84+
// We're connected, log messages via LSP
85+
logger.setConnection(connection);
86+
logger.logRequest('initialize');
7387

7488
// alias options and capabilities
7589
initializationOptions = params.initializationOptions;
7690
capabilities = params.capabilities;
7791

7892
connection.onCompletion(async (params, token): Promise<CompletionItem[]> => {
93+
logger.logRequest('completion');
94+
7995
const document = documents.get(params.textDocument.uri);
8096
if (!document) {
8197
return [];
@@ -85,6 +101,8 @@ connection.onInitialize((params: InitializeParams) => {
85101
})
86102

87103
connection.onHover(async (params, token): Promise<Hover | null | undefined> => {
104+
logger.logRequest('hover');
105+
88106
const document = documents.get(params.textDocument.uri);
89107
if (!document) {
90108
return null;
@@ -94,6 +112,8 @@ connection.onInitialize((params: InitializeParams) => {
94112

95113

96114
connection.onDocumentLinks(async (params, token): Promise<DocumentLink[]> => {
115+
logger.logRequest('documentLinks');
116+
97117
const document = documents.get(params.textDocument.uri);
98118
if (!document) {
99119
return [];
@@ -102,10 +122,13 @@ connection.onInitialize((params: InitializeParams) => {
102122
});
103123

104124
connection.onDocumentLinkResolve(async (link, token): Promise<DocumentLink | undefined> => {
125+
logger.logRequest('documentLinksResolve');
105126
return mdLs?.resolveDocumentLink(link, token);
106127
});
107128

108129
connection.onDocumentSymbol(async (params, token): Promise<DocumentSymbol[]> => {
130+
logger.logRequest('documentSymbol');
131+
109132
const document = documents.get(params.textDocument.uri);
110133
if (!document) {
111134
return [];
@@ -114,6 +137,8 @@ connection.onInitialize((params: InitializeParams) => {
114137
});
115138

116139
connection.onFoldingRanges(async (params, token): Promise<FoldingRange[]> => {
140+
logger.logRequest('foldingRanges');
141+
117142
const document = documents.get(params.textDocument.uri);
118143
if (!document) {
119144
return [];
@@ -122,6 +147,8 @@ connection.onInitialize((params: InitializeParams) => {
122147
});
123148

124149
connection.onSelectionRanges(async (params, token): Promise<SelectionRange[] | undefined> => {
150+
logger.logRequest('selectionRanges');
151+
125152
const document = documents.get(params.textDocument.uri);
126153
if (!document) {
127154
return [];
@@ -130,10 +157,13 @@ connection.onInitialize((params: InitializeParams) => {
130157
});
131158

132159
connection.onWorkspaceSymbol(async (params, token): Promise<WorkspaceSymbol[]> => {
160+
logger.logRequest('workspaceSymbol');
133161
return mdLs?.getWorkspaceSymbols(params.query, token) || [];
134162
});
135163

136164
connection.onReferences(async (params, token): Promise<Location[]> => {
165+
logger.logRequest('references');
166+
137167
const document = documents.get(params.textDocument.uri);
138168
if (!document) {
139169
return [];
@@ -142,6 +172,8 @@ connection.onInitialize((params: InitializeParams) => {
142172
});
143173

144174
connection.onDefinition(async (params, token): Promise<Definition | undefined> => {
175+
logger.logRequest('definition');
176+
145177
const document = documents.get(params.textDocument.uri);
146178
if (!document) {
147179
return undefined;
@@ -182,10 +214,12 @@ connection.onInitialize((params: InitializeParams) => {
182214

183215
// further config dependent initialization
184216
connection.onInitialized(async () => {
217+
logger.logNotification('initialized');
185218

186219
// sync config if possible
187220
if (capabilities?.workspace?.configuration) {
188221
await configManager.subscribe();
222+
logger.setConfigurationManager(configManager);
189223
}
190224

191225
// initialize connection to quarto
@@ -207,12 +241,6 @@ connection.onInitialized(async () => {
207241
);
208242
const quarto = await initializeQuarto(quartoContext);
209243

210-
// initialize logger
211-
const logger = new LogFunctionLogger(
212-
console.log.bind(console),
213-
configManager
214-
);
215-
216244
// initialize workspace
217245
const workspace = languageServiceWorkspace(
218246
workspaceFolders?.map(value => URI.parse(value.uri)) || [],
@@ -255,7 +283,6 @@ connection.onInitialized(async () => {
255283

256284
// register custom methods
257285
registerCustomMethods(quarto, lspConnection, documents);
258-
259286
});
260287

261288

0 commit comments

Comments
 (0)