diff --git a/package.json b/package.json index ca6dc735..8b329bb2 100644 --- a/package.json +++ b/package.json @@ -3509,6 +3509,12 @@ "default": "interpreted", "markdownDescription": "How the analyzer runs. Set from the run-mode button in the status bar and remembered per workspace folder." }, + "analyzer.dictSource": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "On DEV runs, have the engine (4.2.33 or later) record which dictionary file and line built each node, so Rule Fired on a parse tree node opens that dictionary entry." + }, "analyzer.regressionTerminal": { "type": "boolean", "scope": "resource", diff --git a/src/nlp.ts b/src/nlp.ts index e27c3c1c..92a43235 100644 --- a/src/nlp.ts +++ b/src/nlp.ts @@ -17,6 +17,9 @@ import * as telemetry from './telemetry/telemetry'; import { analyzerOutputLines, lastTreePass } from './output/analyzerOutput'; import { generatorChanged, kbOutputsOf } from './session/kbGen'; +// First engine with -DICTSOURCE (nlp-engine#432). +const DICT_SOURCE_ENGINE = '4.2.33'; + let analyzerOutputChannel: vscode.OutputChannel | undefined; /** Show what the analyzer printed with cout() in the "NLP++ Analyzer Output" panel. */ @@ -160,6 +163,15 @@ export class NLPFile extends TextFile { args.push('-COMPILED'); } args.push('"' + filestr + '"', devFlagStr); + // Nodes built from .dict entries then name the entry's file and line, + // so Rule Fired on the tree opens it (#475). Engines before 4.2.33 + // reject the switch and exit, so it goes only to newer ones. + if (mode == DevMode.DEV + && vscode.workspace.getConfiguration('analyzer').get('dictSource', true) + && visualText.engineVersion + && visualText.versionCompare(visualText.engineVersion, DICT_SOURCE_ENGINE) >= 0) { + args.push('-DICTSOURCE'); + } visualText.nlp.setAnalyzerStatus(filepath, analyzerStatus.ANALYZING); diff --git a/src/treeFile.ts b/src/treeFile.ts index a72e1c9a..b1bc0943 100644 --- a/src/treeFile.ts +++ b/src/treeFile.ts @@ -86,12 +86,34 @@ export class TreeFile extends TextFile { // If 0,0, then search inside dictionary files } else if (tline.ruleLine == 0) { - this.searchInDictionaries(tline.node); + if (!this.openDictSource()) + this.searchInDictionaries(tline.node); } } } } + // A run with -DICTSOURCE (engine 4.2.33+) puts the entry that built a + // dictionary node on it: ("dictfile" "words.dict") ("dictline" 14). + // Open that line rather than searching every dictionary (#475). + openDictSource(): boolean { + const line = this.getLines()[this.selStartLine] ?? ''; + const file = /\("dictfile" "([^"]+)"\)/.exec(line); + if (!file) return false; + const dictPath = path.join(visualText.analyzer.getKBDirectory().fsPath, file[1]); + if (!fs.existsSync(dictPath)) return false; + const num = /\("dictline" (\d+)\)/.exec(line); + const lineNum = num ? parseInt(num[1], 10) : 0; + vscode.window.showTextDocument(vscode.Uri.file(dictPath), { viewColumn: vscode.ViewColumn.Beside }).then(edit => { + if (lineNum > 0 && lineNum <= edit.document.lineCount) { + const entry = edit.document.lineAt(lineNum - 1).range; + edit.selections = [new vscode.Selection(entry.start, entry.end)]; + edit.revealRange(entry, vscode.TextEditorRevealType.InCenter); + } + }); + return true; + } + searchInDictionaries(word: string) { const finalMatches: FindItem[] = []; let searchWord = word.toLowerCase();