diff --git a/CHANGELOG.md b/CHANGELOG.md index edf14cabc..7723c4b0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Changes to Calva. ## [Unreleased] +- Maintenance: [Begin work on enabling strictNullChecks in the TypeScript config.](https://github.com/BetterThanTomorrow/calva/pull/1568) ## [2.0.252] - 2022-03-05 - Fix: [Tab doesn't work in snippet mode](https://github.com/BetterThanTomorrow/calva/pull/1580) diff --git a/package.json b/package.json index 1e15b72c9..2e6dc8d2b 100644 --- a/package.json +++ b/package.json @@ -2600,7 +2600,8 @@ "clean": "rimraf ./out && rimraf ./tsconfig.tsbuildinfo && rimraf ./cljs-out", "compile-cljs": "npx shadow-cljs compile :calva-lib :test", "prewatch": "npm i && npm run clean && npm run update-grammar && npm run compile-cljs", - "watch": "npx tsc -watch -p ./tsconfig.json", + "watch": "npx tsc --watch --project ./tsconfig.json", + "watch-with-strict-nulls": "npx tsc --watch --project ./tsconfig.json --strictNullChecks", "release-cljs": "npx shadow-cljs release :calva-lib :test", "update-grammar": "node ./src/calva-fmt/update-grammar.js ./src/calva-fmt/atom-language-clojure/grammars/clojure.cson clojure.tmLanguage.json", "release": "npm i && npm run clean && npm run update-grammar && npm run release-cljs && webpack --mode production", @@ -2687,4 +2688,4 @@ "webpack": "^5.27.1", "webpack-cli": "^4.5.0" } -} +} \ No newline at end of file diff --git a/src/calva-fmt/src/format.ts b/src/calva-fmt/src/format.ts index 000dfe3fc..346e519a8 100644 --- a/src/calva-fmt/src/format.ts +++ b/src/calva-fmt/src/format.ts @@ -3,9 +3,9 @@ import * as config from './config'; import * as outputWindow from '../../results-output/results-doc'; import { getIndent, - getDocument, getDocumentOffset, MirroredDocument, + mustGetDocument, } from '../../doc-mirror/index'; import { formatTextAtRange, @@ -15,15 +15,16 @@ import { cljify, jsify, } from '../../../out/cljs-lib/cljs-lib'; +import * as util from '../../utilities'; export async function indentPosition( position: vscode.Position, document: vscode.TextDocument ) { - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); const pos = new vscode.Position(position.line, 0); const indent = getIndent( - getDocument(document).model.lineInputModel, + mustGetDocument(document).model.lineInputModel, getDocumentOffset(document, position), await config.getConfig() ); @@ -55,7 +56,7 @@ export async function formatRangeEdits( range: vscode.Range ): Promise { const text: string = document.getText(range); - const mirroredDoc: MirroredDocument = getDocument(document); + const mirroredDoc: MirroredDocument = mustGetDocument(document); const startIndex = document.offsetAt(range.start); const endIndex = document.offsetAt(range.end); const cursor = mirroredDoc.getTokenCursor(startIndex); @@ -90,7 +91,7 @@ export async function formatPositionInfo( const doc: vscode.TextDocument = editor.document; const pos: vscode.Position = editor.selection.active; const index = doc.offsetAt(pos); - const mirroredDoc: MirroredDocument = getDocument(doc); + const mirroredDoc: MirroredDocument = mustGetDocument(doc); const cursor = mirroredDoc.getTokenCursor(index); const formatDepth = extraConfig['format-depth'] ? extraConfig['format-depth'] diff --git a/src/calva-fmt/src/providers/ontype_formatter.ts b/src/calva-fmt/src/providers/ontype_formatter.ts index cf2d54c36..ba22fc94f 100644 --- a/src/calva-fmt/src/providers/ontype_formatter.ts +++ b/src/calva-fmt/src/providers/ontype_formatter.ts @@ -4,6 +4,7 @@ import * as docMirror from '../../../doc-mirror/index'; import { EditableDocument } from '../../../cursor-doc/model'; import * as paredit from '../../../cursor-doc/paredit'; import { getConfig } from '../../../config'; +import * as util from '../../../utilities'; export class FormatOnTypeEditProvider implements vscode.OnTypeFormattingEditProvider @@ -14,7 +15,6 @@ export class FormatOnTypeEditProvider ch: string, _options ): Promise { - const editor = vscode.window.activeTextEditor; let keyMap = vscode.workspace .getConfiguration() .get('calva.paredit.defaultKeyMap'); @@ -24,7 +24,8 @@ export class FormatOnTypeEditProvider keyMap === 'strict' && getConfig().strictPreventUnmatchedClosingBracket ) { - const mDoc: EditableDocument = docMirror.getDocument(document); + const mDoc: EditableDocument = + docMirror.mustGetDocument(document); const tokenCursor = mDoc.getTokenCursor(); if (tokenCursor.withinComment()) { return null; @@ -37,6 +38,7 @@ export class FormatOnTypeEditProvider return null; } } + const editor = util.mustGetActiveTextEditor(); const pos = editor.selection.active; if ( diff --git a/src/clojuredocs.ts b/src/clojuredocs.ts index e17f7f13d..69a19aa05 100644 --- a/src/clojuredocs.ts +++ b/src/clojuredocs.ts @@ -63,7 +63,7 @@ export function printTextToRichCommentCommand(args: { [x: string]: string }) { function printTextToRichComment(text: string, position?: number) { const doc = util.getDocument({}); - const mirrorDoc = docMirror.getDocument(doc); + const mirrorDoc = docMirror.mustGetDocument(doc); paredit.addRichComment( mirrorDoc, position ? position : mirrorDoc.selection.active, @@ -183,7 +183,7 @@ async function clojureDocsLookup( p?: vscode.Position ): Promise { const doc = d ? d : util.getDocument({}); - const position = p ? p : vscode.window.activeTextEditor.selection.active; + const position = p ? p : util.mustGetActiveTextEditor().selection.active; const symbol = util.getWordAtPosition(doc, position); const ns = namespace.getNamespace(doc); const session = replSession.getSession(util.getFileType(doc)); diff --git a/src/connector.ts b/src/connector.ts index c52256635..ff8fd40e8 100644 --- a/src/connector.ts +++ b/src/connector.ts @@ -837,7 +837,7 @@ export default { setStateValue('cljc', newSession); if ( outputWindow.isResultsDoc( - vscode.window.activeTextEditor.document + util.mustGetActiveTextEditor().document ) ) { outputWindow.setSession(newSession, undefined); diff --git a/src/custom-snippets.ts b/src/custom-snippets.ts index b47e573fb..1b423f00d 100644 --- a/src/custom-snippets.ts +++ b/src/custom-snippets.ts @@ -15,7 +15,7 @@ async function evaluateCustomCodeSnippetCommand(codeOrKey?: string) { } async function evaluateCodeOrKey(codeOrKey?: string) { - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); const currentLine = editor.selection.active.line; const currentColumn = editor.selection.active.character; const currentFilename = editor.document.fileName; diff --git a/src/debugger/calva-debug.ts b/src/debugger/calva-debug.ts index d74a6680b..c7beced36 100644 --- a/src/debugger/calva-debug.ts +++ b/src/debugger/calva-debug.ts @@ -287,7 +287,7 @@ class CalvaDebugSession extends LoggingDebugSession { new Position(positionLine, positionColumn) ); const tokenCursor = docMirror - .getDocument(document) + .mustGetDocument(document) .getTokenCursor(offset); try { diff --git a/src/debugger/decorations.ts b/src/debugger/decorations.ts index 37a60c186..e1cc7f057 100644 --- a/src/debugger/decorations.ts +++ b/src/debugger/decorations.ts @@ -144,7 +144,7 @@ function triggerUpdateAndRenderDecorations() { timeout = undefined; } if (enabled) { - const editor = vscode.window.activeTextEditor; + const editor = util.getActiveTextEditor(); if (editor) { timeout = setTimeout(() => { const cljSession = replSession.getSession('clj'); @@ -166,7 +166,7 @@ function activate() { }); vscode.workspace.onDidChangeTextDocument((event) => { - const activeEditor = vscode.window.activeTextEditor; + const activeEditor = util.getActiveTextEditor(); if ( activeEditor && event.document === activeEditor.document && diff --git a/src/doc-mirror/index.ts b/src/doc-mirror/index.ts index abd656b5a..ffe3bc0a9 100644 --- a/src/doc-mirror/index.ts +++ b/src/doc-mirror/index.ts @@ -11,6 +11,7 @@ import { LineInputModel, ModelEditSelection, } from '../cursor-doc/model'; +import { isUndefined } from 'lodash'; const documents = new Map(); @@ -28,7 +29,7 @@ export class DocumentModel implements EditableModel { modelEdits: ModelEdit[], options: ModelEditOptions ): Thenable { - const editor = vscode.window.activeTextEditor, + const editor = utilities.mustGetActiveTextEditor(), undoStopBefore = !!options.undoStopBefore; return editor .edit( @@ -84,7 +85,7 @@ export class DocumentModel implements EditableModel { oldSelection?: [number, number], newSelection?: [number, number] ) { - const editor = vscode.window.activeTextEditor, + const editor = utilities.mustGetActiveTextEditor(), document = editor.document; builder.insert(document.positionAt(offset), text); } @@ -97,7 +98,7 @@ export class DocumentModel implements EditableModel { oldSelection?: [number, number], newSelection?: [number, number] ) { - const editor = vscode.window.activeTextEditor, + const editor = utilities.mustGetActiveTextEditor(), document = editor.document, range = new vscode.Range( document.positionAt(start), @@ -113,7 +114,7 @@ export class DocumentModel implements EditableModel { oldSelection?: [number, number], newSelection?: [number, number] ) { - const editor = vscode.window.activeTextEditor, + const editor = utilities.mustGetActiveTextEditor(), document = editor.document, range = new vscode.Range( document.positionAt(offset), @@ -143,13 +144,13 @@ export class MirroredDocument implements EditableDocument { get selectionLeft(): number { return this.document.offsetAt( - vscode.window.activeTextEditor.selection.anchor + utilities.mustGetActiveTextEditor().selection.anchor ); } get selectionRight(): number { return this.document.offsetAt( - vscode.window.activeTextEditor.selection.active + utilities.mustGetActiveTextEditor().selection.active ); } @@ -165,7 +166,7 @@ export class MirroredDocument implements EditableDocument { } public insertString(text: string) { - const editor = vscode.window.activeTextEditor, + const editor = utilities.mustGetActiveTextEditor(), selection = editor.selection, wsEdit = new vscode.WorkspaceEdit(), edit = vscode.TextEdit.insert( @@ -179,7 +180,7 @@ export class MirroredDocument implements EditableDocument { } set selection(selection: ModelEditSelection) { - const editor = vscode.window.activeTextEditor, + const editor = utilities.mustGetActiveTextEditor(), document = editor.document, anchor = document.positionAt(selection.anchor), active = document.positionAt(selection.active); @@ -192,7 +193,7 @@ export class MirroredDocument implements EditableDocument { } public getSelectionText() { - const editor = vscode.window.activeTextEditor, + const editor = utilities.mustGetActiveTextEditor(), selection = editor.selection; return this.document.getText(selection); } @@ -241,11 +242,21 @@ export function getDocument(doc: vscode.TextDocument) { return documents.get(doc); } +export function mustGetDocument(doc: vscode.TextDocument) { + const mirrorDoc = documents.get(doc); + + if (isUndefined(mirrorDoc)) { + throw new Error('Missing mirror document!'); + } + + return mirrorDoc; +} + export function getDocumentOffset( doc: vscode.TextDocument, position: vscode.Position ) { - const model = getDocument(doc).model; + const model = mustGetDocument(doc).model; return model.getOffsetForLine(position.line) + position.character; } diff --git a/src/edit.ts b/src/edit.ts index 87394eef2..0599a71b1 100644 --- a/src/edit.ts +++ b/src/edit.ts @@ -7,9 +7,9 @@ import * as docMirror from './doc-mirror/index'; export function continueCommentCommand() { const document = util.getDocument({}); if (document && document.languageId === 'clojure') { - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); const position = editor.selection.active; - const cursor = docMirror.getDocument(document).getTokenCursor(); + const cursor = docMirror.mustGetDocument(document).getTokenCursor(); if (cursor.getToken().type !== 'comment') { if (cursor.getPrevToken().type === 'comment') { cursor.previous(); diff --git a/src/evaluate.ts b/src/evaluate.ts index f3813de5e..89da492e0 100644 --- a/src/evaluate.ts +++ b/src/evaluate.ts @@ -91,7 +91,7 @@ async function evaluateCode( const filePath = options.filePath; const session: NReplSession = options.session; const ns = options.ns; - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); let result = null; if (code.length > 0) { @@ -259,7 +259,7 @@ async function evaluateSelection(document = {}, options) { ) => [vscode.Selection, string] = options.selectionFn; if (getStateValue('connected')) { - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); state.analytics().logEvent('Evaluation', 'selectionFn').send(); const selection = selectionFn(editor); const codeSelection: vscode.Selection = selection[0]; diff --git a/src/extension-test/integration/suite/extension-test.ts b/src/extension-test/integration/suite/extension-test.ts index c52fe1a0b..dd7fb84ff 100644 --- a/src/extension-test/integration/suite/extension-test.ts +++ b/src/extension-test/integration/suite/extension-test.ts @@ -12,7 +12,7 @@ import * as vscode from 'vscode'; // import * as myExtension from '../extension'; import * as outputWindow from '../../../results-output/results-doc'; import { commands } from 'vscode'; -import { getDocument } from '../../../doc-mirror'; +import { mustGetDocument } from '../../../doc-mirror'; void vscode.window.showInformationMessage('Tests running. Yay!'); @@ -85,7 +85,7 @@ suite('Extension Test Suite', () => { await sleep(500); // wait a little longer for repl output to be done console.log('connected to repl'); - const resultsDoc = getDocument(await outputWindow.openResultsDoc()); + const resultsDoc = mustGetDocument(await outputWindow.openResultsDoc()); // focus the clojure file await vscode.workspace.openTextDocument(testUri).then((doc) => diff --git a/src/file-switcher/file-switcher.ts b/src/file-switcher/file-switcher.ts index 649a2ef56..8aa32dbf4 100644 --- a/src/file-switcher/file-switcher.ts +++ b/src/file-switcher/file-switcher.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import * as util from './util'; import * as projectRoot from '../project-root'; +import { mustGetActiveTextEditor } from '../utilities'; function openFile(file) { return vscode.workspace @@ -39,7 +40,7 @@ function askToCreateANewFile(dir, file) { } export async function toggleBetweenImplAndTest() { - const activeFile = vscode.window.activeTextEditor; + const activeFile = mustGetActiveTextEditor(); const openedFilename = activeFile.document.fileName; const projectRootUri = await projectRoot.getProjectRootUri(); diff --git a/src/highlight/src/extension.ts b/src/highlight/src/extension.ts index 8491b0a62..ffe5ad24c 100755 --- a/src/highlight/src/extension.ts +++ b/src/highlight/src/extension.ts @@ -5,6 +5,7 @@ import { isArray } from 'util'; import * as docMirror from '../../doc-mirror/index'; import { Token, validPair } from '../../cursor-doc/clojure-lexer'; import { LispTokenCursor } from '../../cursor-doc/token-cursor'; +import { getActiveTextEditor, mustGetActiveTextEditor } from '../../utilities'; type StackItem = { char: string; @@ -264,7 +265,7 @@ function updateRainbowBrackets() { } const doc = activeEditor.document, - mirrorDoc = docMirror.getDocument(doc), + mirrorDoc = docMirror.mustGetDocument(doc), rainbow = rainbowTypes.map(() => []), rainbowGuides = rainbowTypes.map(() => []), misplaced = [], @@ -540,7 +541,7 @@ function decorateGuide( function decorateActiveGuides() { const activeGuides = []; - activeEditor = vscode.window.activeTextEditor; + activeEditor = mustGetActiveTextEditor(); if (activeGuidesTypes) { activeGuidesTypes.forEach((type) => activeEditor.setDecorations(type, []) @@ -548,7 +549,7 @@ function decorateActiveGuides() { } activeEditor.selections.forEach((selection) => { const doc = activeEditor.document; - const mirrorDoc = docMirror.getDocument(doc); + const mirrorDoc = docMirror.mustGetDocument(doc); const cursor = mirrorDoc.getTokenCursor(doc.offsetAt(selection.start)); const visitedEndPositions = [selection.start]; findActiveGuide: while (cursor.forwardList() && cursor.upList()) { @@ -585,7 +586,7 @@ function decorateActiveGuides() { } export function activate(context: vscode.ExtensionContext) { - activeEditor = vscode.window.activeTextEditor; + activeEditor = mustGetActiveTextEditor(); vscode.window.onDidChangeActiveTextEditor( (editor) => { @@ -601,7 +602,7 @@ export function activate(context: vscode.ExtensionContext) { vscode.window.onDidChangeTextEditorSelection( (event) => { if ( - event.textEditor === vscode.window.activeTextEditor && + event.textEditor === getActiveTextEditor() && is_clojure(event.textEditor) ) { if (lastHighlightedEditor !== event.textEditor) { diff --git a/src/lsp/main.ts b/src/lsp/main.ts index 73486d471..09ba061f5 100644 --- a/src/lsp/main.ts +++ b/src/lsp/main.ts @@ -299,7 +299,7 @@ function registerLspCommand( (m) => m.substring(1).toUpperCase() )}`; return vscode.commands.registerCommand(vscodeCommand, async () => { - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); const document = util.getDocument(editor.document); if (document && document.languageId === 'clojure') { const line = editor.selection.start.line; @@ -320,7 +320,7 @@ function registerLspCommand( } async function codeLensReferencesHandler(_, line, character): Promise { - vscode.window.activeTextEditor.selection = new vscode.Selection( + util.mustGetActiveTextEditor().selection = new vscode.Selection( line - 1, character - 1, line - 1, @@ -332,12 +332,8 @@ async function codeLensReferencesHandler(_, line, character): Promise { } function resolveMacroAsCommandHandler(): void { - const activeTextEditor = vscode.window.activeTextEditor; - if ( - activeTextEditor && - activeTextEditor.document && - activeTextEditor.document.languageId === 'clojure' - ) { + const activeTextEditor = util.getActiveTextEditor(); + if (activeTextEditor?.document?.languageId === 'clojure') { const documentUri = decodeURIComponent( activeTextEditor.document.uri.toString() ); diff --git a/src/namespace.ts b/src/namespace.ts index 11d97728e..121c53a4d 100644 --- a/src/namespace.ts +++ b/src/namespace.ts @@ -16,7 +16,7 @@ export function getNamespace(doc: vscode.TextDocument) { if (doc && doc.languageId == 'clojure') { try { const cursor: LispTokenCursor = docMirror - .getDocument(doc) + .mustGetDocument(doc) .getTokenCursor(0); cursor.forwardWhitespace(true); let token: Token = null, diff --git a/src/paredit/extension.ts b/src/paredit/extension.ts index a037d994b..2c7ec9def 100644 --- a/src/paredit/extension.ts +++ b/src/paredit/extension.ts @@ -365,7 +365,7 @@ function wrapPareditCommand(command: PareditCommand) { return () => { try { const textEditor = window.activeTextEditor, - mDoc: EditableDocument = docMirror.getDocument( + mDoc: EditableDocument = docMirror.mustGetDocument( textEditor.document ); if (!enabled || !languages.has(textEditor.document.languageId)) { diff --git a/src/providers/annotations.ts b/src/providers/annotations.ts index f999fb2be..7b6eda148 100644 --- a/src/providers/annotations.ts +++ b/src/providers/annotations.ts @@ -95,7 +95,7 @@ function setSelectionDecorations(editor, ranges, status) { } function clearEvaluationDecorations(editor?: vscode.TextEditor) { - editor = editor || vscode.window.activeTextEditor; + editor = editor || util.getActiveTextEditor(); if (editor) { util.cljsLib.removeStateValue( editor.document.uri + ':resultDecorationRanges' @@ -204,8 +204,7 @@ function decorateSelection( function onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { if (event.contentChanges.length) { - const activeTextEditor: vscode.TextEditor = - vscode.window.activeTextEditor; + const activeTextEditor: vscode.TextEditor = util.getActiveTextEditor(); if (activeTextEditor) { const activeDocument = activeTextEditor.document, changeDocument = event.document; diff --git a/src/providers/completion.ts b/src/providers/completion.ts index 4296f151b..896d3c584 100644 --- a/src/providers/completion.ts +++ b/src/providers/completion.ts @@ -49,7 +49,7 @@ export async function provideCompletionItems( toplevel = document.getText(toplevelSelection), toplevelStartOffset = document.offsetAt(toplevelSelection.start), toplevelStartCursor = docMirror - .getDocument(document) + .mustGetDocument(document) .getTokenCursor(toplevelStartOffset + 1), wordRange = document.getWordRangeAtPosition(position), wordStartLocalOffset = diff --git a/src/providers/hover.ts b/src/providers/hover.ts index 45c324cbe..d4ab94955 100644 --- a/src/providers/hover.ts +++ b/src/providers/hover.ts @@ -34,7 +34,7 @@ export async function provideHover( hovers.push(docsMd, clojureDocsMd); } - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); const context = { ns, diff --git a/src/providers/signature.ts b/src/providers/signature.ts index b868a36fd..22ee10ffc 100644 --- a/src/providers/signature.ts +++ b/src/providers/signature.ts @@ -75,7 +75,7 @@ export async function provideSignatureHelp( function getCurrentArgsRanges(document: TextDocument, idx: number): Range[] { const cursor: LispTokenCursor = docMirror - .getDocument(document) + .mustGetDocument(document) .getTokenCursor(idx), allRanges = cursor.rowColRangesForSexpsInList('('); @@ -112,7 +112,7 @@ function getActiveSignatureIdx( function getSymbol(document: TextDocument, idx: number): string { const cursor: LispTokenCursor = docMirror - .getDocument(document) + .mustGetDocument(document) .getTokenCursor(idx); return cursor.getFunctionName(); } @@ -123,7 +123,7 @@ function coordsToRange(coords: [[number, number], [number, number]]): Range { function getPreviousRangeIndexAndFunction(document: TextDocument, idx: number) { const peekBehindCursor: LispTokenCursor = docMirror - .getDocument(document) + .mustGetDocument(document) .getTokenCursor(idx); peekBehindCursor.backwardFunction(1); const previousFunction = peekBehindCursor.getFunctionName(0), diff --git a/src/results-output/repl-history.ts b/src/results-output/repl-history.ts index a154de79c..c91962ca5 100644 --- a/src/results-output/repl-history.ts +++ b/src/results-output/repl-history.ts @@ -117,7 +117,7 @@ function prependNewline(text: string) { } function showPreviousReplHistoryEntry(): void { - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); const doc = editor.document; const replSessionType = getSessionType(); const history = getHistory(replSessionType); @@ -139,7 +139,7 @@ function showPreviousReplHistoryEntry(): void { } function showNextReplHistoryEntry(): void { - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); const doc = editor.document; const replSessionType = getSessionType(); const history = getHistory(replSessionType); diff --git a/src/results-output/results-doc.ts b/src/results-output/results-doc.ts index 25d1bf4ca..18e850b3c 100644 --- a/src/results-output/results-doc.ts +++ b/src/results-output/results-doc.ts @@ -186,7 +186,7 @@ export async function initResultsDoc(): Promise { const document = event.textEditor.document; if (isResultsDoc(document)) { const idx = document.offsetAt(event.selections[0].active); - const mirrorDoc = docMirror.getDocument(document); + const mirrorDoc = docMirror.mustGetDocument(document); const selectionCursor = mirrorDoc.getTokenCursor(idx); selectionCursor.forwardWhitespace(); if (selectionCursor.atEnd()) { @@ -219,14 +219,10 @@ export async function initResultsDoc(): Promise { // If the output window is active when initResultsDoc is run, these contexts won't be set properly without the below // until the next time it's focused - if ( - vscode.window.activeTextEditor && - isResultsDoc(vscode.window.activeTextEditor.document) - ) { + const activeTextEditor = util.getActiveTextEditor(); + if (activeTextEditor && isResultsDoc(activeTextEditor.document)) { setContextForOutputWindowActive(true); - replHistory.setReplHistoryCommandsActiveContext( - vscode.window.activeTextEditor - ); + replHistory.setReplHistoryCommandsActiveContext(activeTextEditor); } replHistory.resetState(); isInitialized = true; @@ -270,7 +266,7 @@ export async function setNamespaceFromCurrentFile() { async function appendFormGrabbingSessionAndNS(topLevel: boolean) { const session = replSession.getSession(); const ns = namespace.getNamespace(util.getDocument({})); - const editor = vscode.window.activeTextEditor; + const editor = util.mustGetActiveTextEditor(); const doc = editor.document; const selection = editor.selection; let code = ''; diff --git a/src/select.ts b/src/select.ts index 6242392f4..82f456358 100644 --- a/src/select.ts +++ b/src/select.ts @@ -18,7 +18,7 @@ function getFormSelection( topLevel: boolean ): vscode.Selection { const idx = doc.offsetAt(pos); - const cursor = docMirror.getDocument(doc).getTokenCursor(idx); + const cursor = docMirror.mustGetDocument(doc).getTokenCursor(idx); const range = topLevel ? cursor.rangeForDefun(idx) : cursor.rangeForCurrentForm(idx); @@ -32,7 +32,7 @@ function getEnclosingFormSelection( pos: vscode.Position ): vscode.Selection { const idx = doc.offsetAt(pos); - const cursor = docMirror.getDocument(doc).getTokenCursor(idx); + const cursor = docMirror.mustGetDocument(doc).getTokenCursor(idx); if (cursor.backwardList()) { cursor.backwardUpList(); const start = cursor.offsetStart; @@ -52,7 +52,7 @@ function selectForm( ) => vscode.Selection, toplevel: boolean ) { - const editor = vscode.window.activeTextEditor, + const editor = util.mustGetActiveTextEditor(), doc = util.getDocument(document), selection = editor.selection; diff --git a/src/testRunner.ts b/src/testRunner.ts index 68c371ec1..702727b3e 100644 --- a/src/testRunner.ts +++ b/src/testRunner.ts @@ -359,7 +359,7 @@ async function runNamespaceTests( } function getTestUnderCursor() { - const editor = vscode.window.activeTextEditor; + const editor = util.getActiveTextEditor(); if (editor) { return getText.currentTopLevelFunction(editor?.document)[1]; } @@ -406,7 +406,7 @@ function runNamespaceTestsCommand(controller: vscode.TestController) { } runNamespaceTests( controller, - vscode.window.activeTextEditor.document + util.mustGetActiveTextEditor().document ).catch((msg) => { void vscode.window.showWarningMessage(msg); }); @@ -474,7 +474,7 @@ function initialize(controller: vscode.TestController): void { // The next steps here would be to turn request.exclude and requst.include // into a Cider var-query that can be passed to test-var query directly. const namespaces = util.distinct(runItems.map((ri) => ri[0])); - const doc = vscode.window.activeTextEditor.document; + const doc = util.mustGetActiveTextEditor().document; runNamespaceTestsImpl(controller, doc, namespaces).catch((msg) => { void vscode.window.showWarningMessage(msg); }); diff --git a/src/util/get-text.ts b/src/util/get-text.ts index f540f2916..3d19f93f3 100644 --- a/src/util/get-text.ts +++ b/src/util/get-text.ts @@ -46,7 +46,7 @@ export function currentEnclosingFormText( export function currentFunction(doc: vscode.TextDocument): SelectionAndText { if (doc) { - const tokenCursor = docMirror.getDocument(doc).getTokenCursor(); + const tokenCursor = docMirror.mustGetDocument(doc).getTokenCursor(); const [start, end] = tokenCursor.getFunctionSexpRange(); if (start && end) { const startPos = doc.positionAt(start); @@ -63,7 +63,7 @@ function selectionAndText( textGetter: (doc: EditableDocument) => cursorTextGetter.RangeAndText ): SelectionAndText { if (doc) { - const mirrorDoc = docMirror.getDocument(doc); + const mirrorDoc = docMirror.mustGetDocument(doc); const [range, text] = textGetter(mirrorDoc); if (range) { return [select.selectionFromOffsetRange(doc, range), text]; @@ -99,7 +99,7 @@ function fromFn( cursorDocFn: (doc: EditableDocument, offset?: number) => [number, number] ): SelectionAndText { if (doc) { - const cursorDoc = docMirror.getDocument(doc); + const cursorDoc = docMirror.mustGetDocument(doc); const range = cursorDocFn(cursorDoc); const selection = select.selectionFromOffsetRange(doc, range); const text = doc.getText(selection); diff --git a/src/utilities.ts b/src/utilities.ts index f3b04f023..49f0dec0f 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -9,6 +9,7 @@ import * as JSZip from 'jszip'; import * as outputWindow from './results-output/results-doc'; import * as cljsLib from '../out/cljs-lib/cljs-lib'; import * as url from 'url'; +import { isUndefined } from 'lodash'; const specialWords = ['-', '+', '/', '*']; //TODO: Add more here const syntaxQuoteSymbol = '`'; @@ -174,17 +175,17 @@ function getWordAtPosition(document, position) { function getDocument( document: vscode.TextDocument | Record ): vscode.TextDocument { + const activeTextEditor = getActiveTextEditor(); if ( document && Object.prototype.hasOwnProperty.call(document, 'fileName') ) { return document as vscode.TextDocument; } else if ( - vscode.window.activeTextEditor && - vscode.window.activeTextEditor.document && - vscode.window.activeTextEditor.document.languageId !== 'Log' + activeTextEditor?.document && + activeTextEditor.document.languageId !== 'Log' ) { - return vscode.window.activeTextEditor.document; + return activeTextEditor.document; } else if (vscode.window.visibleTextEditors.length > 0) { const editor = vscode.window.visibleTextEditors.find( (editor) => editor.document && editor.document.languageId !== 'Log' @@ -297,7 +298,7 @@ function markError(error) { } const diagnostic = cljsLib.getStateValue('diagnosticCollection'), - editor = vscode.window.activeTextEditor; + editor = mustGetActiveTextEditor(); //editor.selection = new vscode.Selection(position, position); const line = error.line - 1, @@ -346,7 +347,7 @@ function markWarning(warning) { } const diagnostic = cljsLib.getStateValue('diagnosticCollection'), - editor = vscode.window.activeTextEditor; + editor = mustGetActiveTextEditor(); //editor.selection = new vscode.Selection(position, position); const line = Math.max(0, warning.line - 1), @@ -556,6 +557,20 @@ function distinct(coll: T[]): T[] { return [...new Set(coll)]; } +function getActiveTextEditor(): vscode.TextEditor | undefined { + return vscode.window.activeTextEditor; +} + +function mustGetActiveTextEditor(): vscode.TextEditor { + const editor = getActiveTextEditor(); + + if (isUndefined(editor)) { + throw new Error('Expected active text editor!'); + } + + return editor; +} + export { distinct, getWordAtPosition, @@ -592,4 +607,6 @@ export { cljsLib, randomSlug, isWindows, + getActiveTextEditor, + mustGetActiveTextEditor, }; diff --git a/src/when-contexts.ts b/src/when-contexts.ts index 51fedd69c..6fbe8a671 100644 --- a/src/when-contexts.ts +++ b/src/when-contexts.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { deepEqual } from './util/object'; import * as docMirror from './doc-mirror'; import * as context from './cursor-doc/cursor-context'; +import * as util from './utilities'; let lastContexts: context.CursorContext[] = []; @@ -10,7 +11,7 @@ export default function setCursorContextIfChanged(editor: vscode.TextEditor) { !editor || !editor.document || editor.document.languageId !== 'clojure' || - editor !== vscode.window.activeTextEditor + editor !== util.getActiveTextEditor() ) { return; } @@ -27,7 +28,7 @@ function determineCursorContexts( document: vscode.TextDocument, position: vscode.Position ): context.CursorContext[] { - const mirrorDoc = docMirror.getDocument(document); + const mirrorDoc = docMirror.mustGetDocument(document); return context.determineContexts(mirrorDoc, document.offsetAt(position)); }