From 710da284189b431d28b661dde1e8189cca6f57a6 Mon Sep 17 00:00:00 2001 From: elliot Date: Fri, 8 May 2026 12:46:05 -0400 Subject: [PATCH] Add setting and command to show/hide cells in outline --- apps/lsp/src/config.ts | 10 ++++- apps/lsp/src/service/config.ts | 4 +- apps/lsp/src/service/index.ts | 2 +- .../src/service/providers/document-symbols.ts | 22 +++++++++- apps/vscode/package.json | 10 +++++ apps/vscode/src/main.ts | 3 ++ apps/vscode/src/providers/symbols.ts | 44 +++++++++++++++++++ 7 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 apps/vscode/src/providers/symbols.ts diff --git a/apps/lsp/src/config.ts b/apps/lsp/src/config.ts index cd8941fa..4c870b81 100644 --- a/apps/lsp/src/config.ts +++ b/apps/lsp/src/config.ts @@ -47,6 +47,7 @@ export interface Settings { }; readonly symbols: { readonly exportToWorkspace: 'default' | 'all' | 'none'; + readonly showCodeCellsInOutline: boolean; }; }; readonly markdown: { @@ -96,7 +97,8 @@ function defaultSettings(): Settings { extensions: [] }, symbols: { - exportToWorkspace: 'all' + exportToWorkspace: 'all', + showCodeCellsInOutline: true } }, markdown: { @@ -181,7 +183,8 @@ export class ConfigurationManager extends Disposable { extensions: quarto?.mathjax?.extensions ?? this._settings.quarto.mathjax.extensions }, symbols: { - exportToWorkspace: quarto?.symbols?.exportToWorkspace ?? this._settings.quarto.symbols.exportToWorkspace + exportToWorkspace: quarto?.symbols?.exportToWorkspace ?? this._settings.quarto.symbols.exportToWorkspace, + showCodeCellsInOutline: quarto?.symbols?.showCodeCellsInOutline ?? this._settings.quarto.symbols.showCodeCellsInOutline } } }; @@ -258,6 +261,9 @@ export function lsConfiguration(configManager: ConfigurationManager): LsConfigur }, get exportSymbolsToWorkspace(): 'default' | 'all' | 'none' { return configManager.getSettings().quarto.symbols.exportToWorkspace; + }, + get showCodeCellsInOutline(): boolean { + return configManager.getSettings().quarto.symbols.showCodeCellsInOutline; } }; } diff --git a/apps/lsp/src/service/config.ts b/apps/lsp/src/service/config.ts index 14404470..0f2ddbcd 100644 --- a/apps/lsp/src/service/config.ts +++ b/apps/lsp/src/service/config.ts @@ -80,6 +80,7 @@ export interface LsConfiguration { readonly mathjaxScale: number; readonly mathjaxExtensions: readonly MathjaxSupportedExtension[]; readonly exportSymbolsToWorkspace: 'default' | 'all' | 'none'; + readonly showCodeCellsInOutline: boolean; } export const defaultMarkdownFileExtension = 'qmd'; @@ -111,7 +112,8 @@ const defaultConfig: LsConfiguration = { colorTheme: 'light', mathjaxScale: 1, mathjaxExtensions: [], - exportSymbolsToWorkspace: 'all' + exportSymbolsToWorkspace: 'all', + showCodeCellsInOutline: true }; export function defaultLsConfiguration(): LsConfiguration { diff --git a/apps/lsp/src/service/index.ts b/apps/lsp/src/service/index.ts index 1c6b4003..6544891c 100644 --- a/apps/lsp/src/service/index.ts +++ b/apps/lsp/src/service/index.ts @@ -208,7 +208,7 @@ export function createLanguageService(init: LanguageServiceInitialization): IMdL const definitionsProvider = new MdDefinitionProvider(config, init.workspace, tocProvider, linkCache); const diagnosticOnSaveComputer = new DiagnosticOnSaveComputer(init.quarto); const diagnosticsComputer = new DiagnosticComputer(config, init.workspace, linkProvider, tocProvider, logger); - const docSymbolProvider = new MdDocumentSymbolProvider(tocProvider, linkProvider, logger); + const docSymbolProvider = new MdDocumentSymbolProvider(config, tocProvider, linkProvider, logger); const workspaceSymbolProvider = new MdWorkspaceSymbolProvider(init.workspace, init.config, docSymbolProvider); const documentHighlightProvider = new MdDocumentHighlightProvider(config, tocProvider, linkProvider); diff --git a/apps/lsp/src/service/providers/document-symbols.ts b/apps/lsp/src/service/providers/document-symbols.ts index 678a8a1a..91b120d4 100644 --- a/apps/lsp/src/service/providers/document-symbols.ts +++ b/apps/lsp/src/service/providers/document-symbols.ts @@ -16,9 +16,10 @@ import { CancellationToken } from 'vscode-languageserver'; import * as lsp from 'vscode-languageserver-types'; import { isBefore, makeRange, Document } from 'quarto-core'; -import { ILogger, LogLevel } from '../logging'; +import { ILogger } from '../logging'; import { MdTableOfContentsProvider, TableOfContents, TocEntry, TocEntryType } from '../toc'; import { MdLinkDefinition, MdLinkKind, MdLinkProvider } from './document-links'; +import { LsConfiguration } from '../config'; interface MarkdownSymbol { readonly level: number; @@ -36,12 +37,15 @@ export class MdDocumentSymbolProvider { readonly #tocProvider: MdTableOfContentsProvider; readonly #linkProvider: MdLinkProvider; readonly #logger: ILogger; + readonly #config: LsConfiguration; constructor( + config: LsConfiguration, tocProvider: MdTableOfContentsProvider, linkProvider: MdLinkProvider, logger: ILogger, ) { + this.#config = config; this.#tocProvider = tocProvider; this.#linkProvider = linkProvider; this.#logger = logger; @@ -75,7 +79,21 @@ export class MdDocumentSymbolProvider { range: makeRange(0, 0, document.lineCount + 1, 0), }; const additionalSymbols = [...linkSymbols]; - this.#buildTocSymbolTree(root, toc.entries.filter(entry => entry.type !== TocEntryType.Title), additionalSymbols); + + // Filter out TOC entries based on configuration + const filteredEntries = toc.entries.filter(entry => { + // Always exclude title entries + if (entry.type === TocEntryType.Title) { + return false; + } + // Exclude all code cells if the setting is disabled + if (entry.type === TocEntryType.CodeCell && !this.#config.showCodeCellsInOutline) { + return false; + } + return true; + }); + + this.#buildTocSymbolTree(root, filteredEntries, additionalSymbols); // Put remaining link definitions into top level document instead of last header root.children.push(...additionalSymbols); return root.children; diff --git a/apps/vscode/package.json b/apps/vscode/package.json index 596dbe84..c5606fd3 100644 --- a/apps/vscode/package.json +++ b/apps/vscode/package.json @@ -292,6 +292,11 @@ "title": "Clear Cache...", "category": "Quarto" }, + { + "command": "quarto.toggleCodeCellsInOutline", + "title": "Toggle Code Cells in Outline", + "category": "Quarto" + }, { "command": "quarto.convertToIpynb", "title": "Convert to .ipynb", @@ -1364,6 +1369,11 @@ ], "default": "default", "description": "Whether Markdown elements like section headers are included in workspace symbol search." + }, + "quarto.symbols.showCodeCellsInOutline": { + "type": "boolean", + "default": true, + "description": "Show code cells in the document outline." } } }, diff --git a/apps/vscode/src/main.ts b/apps/vscode/src/main.ts index e4eca1d7..d24465aa 100644 --- a/apps/vscode/src/main.ts +++ b/apps/vscode/src/main.ts @@ -40,6 +40,7 @@ import { activateDenoConfig } from "./providers/deno-config"; import { textFormattingCommands } from "./providers/text-format"; import { newDocumentCommands } from "./providers/newdoc"; import { insertCommands } from "./providers/insert"; +import { symbolsCommands } from "./providers/symbols"; import { activateDiagram } from "./providers/diagram/diagram"; import { activateCodeFormatting } from "./providers/format"; import { activateOptionEnterProvider } from "./providers/option"; @@ -157,6 +158,8 @@ export async function activate(context: vscode.ExtensionContext): Promise("symbols.showCodeCellsInOutline", true); + const newValue = !currentValue; + + await config.update("symbols.showCodeCellsInOutline", newValue, vscode.ConfigurationTarget.Global); + + // Hack: trigger outline refresh by making a no-op edit + const editor = vscode.window.activeTextEditor; + if (editor && editor.document.languageId === "quarto") { + await editor.edit(edit => edit.insert(new vscode.Position(0, 0), " ")); + await editor.edit(edit => edit.delete(new vscode.Range(0, 0, 0, 1))); + } + + vscode.window.showInformationMessage( + `Code cells in outline will now be ${newValue ? "shown" : "hidden"}.` + ); + } +} + +export function symbolsCommands(): Command[] { + return [new ToggleCodeCellsInOutlineCommand()]; +}