diff --git a/apps/vscode/CHANGELOG.md b/apps/vscode/CHANGELOG.md
index 490e1432..89c6d2ee 100644
--- a/apps/vscode/CHANGELOG.md
+++ b/apps/vscode/CHANGELOG.md
@@ -3,7 +3,7 @@
 ## 1.118.0 (unreleased)
 
 - Provide F1 help at cursor in Positron (<https://github.com/quarto-dev/quarto/pull/599>)
-- Expose new context keys for the language of a specific cell (<https://github.com/quarto-dev/quarto/pull/607>)
+- Expose new context keys for the main language of a document (<https://github.com/quarto-dev/quarto/pull/608>)
 - No longer send all snippet suggestions to the bottom of the completion list (<https://github.com/quarto-dev/quarto/pull/609>).
 
 ## 1.117.0 (Release on 2024-11-07)
diff --git a/apps/vscode/src/extension.ts b/apps/vscode/src/extension.ts
index 251db7b9..b85e7e2b 100644
--- a/apps/vscode/src/extension.ts
+++ b/apps/vscode/src/extension.ts
@@ -23,6 +23,7 @@ import { activateDiagram } from "./providers/diagram/diagram";
 import { activateOptionEnterProvider } from "./providers/option";
 import { textFormattingCommands } from "./providers/text-format";
 import { activateCodeFormatting } from "./providers/format";
+import { activateContextKeySetter } from "./providers/context-keys";
 import { ExtensionHost } from "./host";
 
 export function activateCommon(
@@ -37,6 +38,9 @@ export function activateCommon(
   // background highlighter
   activateBackgroundHighlighter(context, engine);
 
+  // context setter
+  activateContextKeySetter(context, engine);
+
   // diagramming
   const diagramCommands = activateDiagram(context, host, engine);
 
diff --git a/apps/vscode/src/providers/context-keys.ts b/apps/vscode/src/providers/context-keys.ts
new file mode 100644
index 00000000..7b7dca6b
--- /dev/null
+++ b/apps/vscode/src/providers/context-keys.ts
@@ -0,0 +1,69 @@
+/*
+ * context-keys.ts
+ *
+ * Copyright (C) 2024 by Posit Software, PBC
+ *
+ * Unless you have received this program directly from Posit Software pursuant
+ * to the terms of a commercial license agreement with Posit Software, then
+ * this program is licensed to you under the terms of version 3 of the
+ * GNU Affero General Public License. This program is distributed WITHOUT
+ * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
+ * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
+ *
+ */
+
+import * as vscode from "vscode";
+import debounce from "lodash.debounce";
+
+import { isQuartoDoc } from "../core/doc";
+import { MarkdownEngine } from "../markdown/engine";
+import { mainLanguage } from "../vdoc/vdoc";
+
+const debounceOnDidChangeDocumentMs = 250;
+
+export function activateContextKeySetter(
+  context: vscode.ExtensionContext,
+  engine: MarkdownEngine
+) {
+
+  // set context keys when active text editor changes
+  vscode.window.onDidChangeActiveTextEditor(
+    (editor) => {
+      if (editor) {
+        setContextKeys(editor, engine);
+      }
+    },
+    null,
+    context.subscriptions
+  );
+
+  // set context keys on changes to the document (if it's active)
+  vscode.workspace.onDidChangeTextDocument(
+    (event) => {
+      const activeEditor = vscode.window.activeTextEditor;
+      if (activeEditor) {
+        debounce(
+          () => setContextKeys(activeEditor, engine),
+          debounceOnDidChangeDocumentMs
+        )();
+      }
+    },
+    null,
+    context.subscriptions
+  );
+}
+
+function setContextKeys(editor: vscode.TextEditor, engine: MarkdownEngine) {
+  if (!editor || !isQuartoDoc(editor.document)) {
+    return;
+  }
+
+  // expose main language for use in keybindings, etc
+  const tokens = engine.parse(editor.document);
+  const language = mainLanguage(tokens);
+  vscode.commands.executeCommand(
+    'setContext',
+    'quarto.document.languageId',
+    language?.ids[0]);
+}
diff --git a/apps/vscode/src/vdoc/vdoc.ts b/apps/vscode/src/vdoc/vdoc.ts
index 4e011fd6..bfe942a9 100644
--- a/apps/vscode/src/vdoc/vdoc.ts
+++ b/apps/vscode/src/vdoc/vdoc.ts
@@ -13,7 +13,7 @@
  *
  */
 
-import { Position, TextDocument, Uri, Range, commands } from "vscode";
+import { Position, TextDocument, Uri, Range } from "vscode";
 import { Token, isExecutableLanguageBlock, languageBlockAtPosition, languageNameFromBlock } from "quarto-core";
 
 import { isQuartoDoc } from "../core/doc";
@@ -157,12 +157,8 @@ export async function virtualDocUri(
 export function languageAtPosition(tokens: Token[], position: Position) {
   const block = languageBlockAtPosition(tokens, position);
   if (block) {
-    const language = languageFromBlock(block);
-    // expose cell language for use in keybindings, etc
-    commands.executeCommand('setContext', 'quarto.cellLangId', language?.ids[0]);
-    return language;
+    return languageFromBlock(block);
   } else {
-    commands.executeCommand('setContext', 'quarto.cellLangId', undefined);
     return undefined;
   }
 }