Skip to content

Commit

Permalink
Add lgtdoc tool warnings to the "Problems" pane
Browse files Browse the repository at this point in the history
  • Loading branch information
pmoura committed May 8, 2024
1 parent b334f01 commit 46c3a57
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* Add "Logtalk: Scan Dead Code (workspace)" command
* Add `dead_code_scanner` tool warnings to the "Problems" pane
* Add `lgtdoc` tool warnings to the "Problems" pane
* Update the "Known Issues" section in the readme file

## [0.20.0]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ Diagrams script for converting the `.dot` files generated by the Logtalk `diagra

"logtalk.scripts.timeout": 480000

The number of milliseconds to wait before running the scripts that convert `.xml` documentation files and `.dot` diagram files to final formats when running the `lgtdoc` and `diagrams` tools. This timeout is also used to wait for a file compilation to finish before adding any compiler errors or warnings to the "Problems" pane and for waiting to answers from the Logtalk reflection API when using code navigation features. You may need to set a value larger than the default value if you're compiling big applications.
The number of milliseconds to wait before running the scripts that convert `.xml` documentation files and `.dot` diagram files to final formats when running the `lgtdoc` and `diagrams` tools. This timeout is also used to wait for a file compilation to finish before adding any compiler and tool errors or warnings to the "Problems" pane and for waiting to answers from the Logtalk reflection API when using code navigation features. You may need to set a value larger than the default value if you're compiling big applications.

## Known Issues

Expand Down
7 changes: 5 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import LogtalkDocumentHighlightProvider from "./features/documentHighlightProvid
import LogtalkTerminal from "./features/logtalkTerminal";
import LogtalkLinter from "./features/logtalkLinter";
import LogtalkDeadCodeScanner from "./features/logtalkDeadCodeScanner";
import LogtalkDocumentationLinter from "./features/logtalkDocumentationLinter";
import LogtalkHoverProvider from "./features/hoverProvider";
import { LogtalkDeclarationProvider } from "./features/declarationProvider";
import { LogtalkDefinitionProvider } from "./features/definitionProvider";
Expand All @@ -40,8 +41,10 @@ export function activate(context: ExtensionContext) {
linter.activate(subscriptions);
const deadCodeScanner = new LogtalkDeadCodeScanner(context);
deadCodeScanner.activate(subscriptions);
const documentationLinter = new LogtalkDocumentationLinter(context);
documentationLinter.activate(subscriptions);

DEBUG ? console.log('Linter Loaded.') : null;
DEBUG ? console.log('Linters loaded') : null;

Utils.init(context);

Expand All @@ -53,7 +56,7 @@ export function activate(context: ExtensionContext) {
{ command: "logtalk.run.tests", callback: uri => LogtalkTerminal.runTests(uri)},
{ command: "logtalk.run.doclet", callback: uri => LogtalkTerminal.runDoclet(uri)},
{ command: "logtalk.scan.deadCode", callback: uri => LogtalkTerminal.scanForDeadCode(uri, deadCodeScanner)},
{ command: "logtalk.generate.documentation", callback: uri => LogtalkTerminal.genDocumentation(uri)},
{ command: "logtalk.generate.documentation", callback: uri => LogtalkTerminal.genDocumentation(uri, documentationLinter)},
{ command: "logtalk.generate.diagrams", callback: uri => LogtalkTerminal.genDiagrams(uri)},
{ command: "logtalk.open", callback: () => LogtalkTerminal.openLogtalk()},
{ command: "logtalk.rscan.deadCode", callback: uri => LogtalkTerminal.rscanForDeadCode(uri, deadCodeScanner)},
Expand Down
186 changes: 186 additions & 0 deletions src/features/logtalkDocumentationLinter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
"use strict";

import {
CancellationToken,
CodeActionContext,
CodeActionProvider,
Command,
Diagnostic,
DiagnosticCollection,
DiagnosticSeverity,
Disposable,
ExtensionContext,
languages,
OutputChannel,
Position,
Range,
Selection,
TextDocument,
TextEditorRevealType,
Uri,
window,
workspace,
WorkspaceEdit
} from "vscode";
import * as path from "path";

import LogtalkTerminal from "./logtalkTerminal";

export default class LogtalkDocumentationLinter implements CodeActionProvider {

public diagnosticCollection: DiagnosticCollection;
public diagnostics: { [docName: string]: Diagnostic[] } = {};
public diagnosticHash = [];
private filePathIds: { [id: string]: string } = {};
private sortedDiagIndex: { [docName: string]: number[] } = {};
private msgRegex = /(((\*|\!)\s{5}.+\n[\*|\!]\s{7}.+\n)|((\*|\!)\s{5}.+\n))[\*|\!]\s{7}.+\n[\*|\!]\s{7}in file\s(.+)\s(below line\s(\d+))/;
private executable: string;
private documentListener: Disposable;
private openDocumentListener: Disposable;
public outputChannel: OutputChannel = null;

constructor(private context: ExtensionContext) {
this.executable = null;
this.loadConfiguration();
}

provideCodeActions(
document: TextDocument,
range: Range,
context: CodeActionContext,
token: CancellationToken
): Command[] | Thenable<Command[]> {
let codeActions: Command[] = [];
return codeActions;
}
private parseIssue(issue: string) {

if(this.diagnosticHash.includes(issue)) {
return true
} else {
this.diagnosticHash.push(issue)
}

let match = issue.match(this.msgRegex)
if (match == null) { return null; } else { console.log("match!"); }

let severity: DiagnosticSeverity;
if(match[0][0] == '*') {
severity = DiagnosticSeverity.Warning
} else {
severity = DiagnosticSeverity.Error
}
console.log(severity);

let fileName = path.resolve(match[6]);
console.log(fileName);
let lineFrom = 0,
lineTo = 0;
console.log(match)

if(match[8]) {
lineFrom = parseInt(match[8])-1;
lineTo = parseInt(match[8]);
}

let fromCol = 0;
let toCol = 240; // Default horizontal range
let fromPos = new Position(lineFrom, fromCol);
let toPos = new Position(lineTo, toCol);
let range = new Range(fromPos, toPos);
let errMsg = match[1].replace(new RegExp(/\* /,'g'), '').replace(new RegExp(/\! /,'g'), '');
let diag = new Diagnostic(range, errMsg, severity);

if (diag) {
if (!this.diagnostics[fileName]) {
this.diagnostics[fileName] = [diag];
} else {
this.diagnostics[fileName].push(diag);
}
}

}

public lint(textDocument: TextDocument, message) {
this.parseIssue(message);
this.diagnosticCollection.delete(textDocument.uri);

for (let doc in this.diagnostics) {
let index = this.diagnostics[doc]
.map((diag, i) => {
return [diag.range.start.line, i];
})
.sort((a, b) => {
return a[0] - b[0];
});
this.sortedDiagIndex[doc] = index.map(item => {
return item[1];
});
this.diagnosticCollection.set(Uri.file(doc), this.diagnostics[doc]);
}
for (let doc in this.sortedDiagIndex) {
let si = this.sortedDiagIndex[doc];
for (let i = 0; i < si.length; i++) {
let diag = this.diagnostics[doc][si[i]];
let severity = diag.severity === DiagnosticSeverity.Error ? "ERROR" : "Warning";
this.outputChannel.append(message)
}
if (si.length > 0) {
this.outputChannel.show(true);
}
}
}

private loadConfiguration(): void {
let section = workspace.getConfiguration("logtalk");
if (section) {
this.executable = section.get<string>("executable.path", "logtalk");
if (this.documentListener) {
this.documentListener.dispose();
}
if (this.openDocumentListener) {
this.openDocumentListener.dispose();
}
}
}

public activate(subscriptions): void {

this.diagnosticCollection = languages.createDiagnosticCollection('Logtalk Documentation Linter');

workspace.onDidChangeConfiguration(
this.loadConfiguration,
this,
subscriptions
);

if (this.outputChannel === null) {
this.outputChannel = window.createOutputChannel("Logtalk Documentation Linter");
this.outputChannel.clear();
}

this.loadConfiguration();

// workspace.onDidOpenTextDocument(this.doPlint, this, subscriptions);
workspace.onDidCloseTextDocument(
textDocument => {
this.diagnosticCollection.delete(textDocument.uri);
},
null,
subscriptions
);
}

private outputMsg(msg: string) {
this.outputChannel.append(msg + "\n");
this.outputChannel.show(true);
}

public dispose(): void {
this.documentListener.dispose();
this.openDocumentListener.dispose();
this.diagnosticCollection.clear();
this.diagnosticCollection.dispose();
}

}
31 changes: 30 additions & 1 deletion src/features/logtalkTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as fs from "fs";
import { spawn } from "process-promises";
import LogtalkLinter from "./logtalkLinter";
import LogtalkDeadCodeScanner from "./logtalkDeadCodeScanner";
import LogtalkDocumentationLinter from "./logtalkDocumentationLinter";
import { isFunction } from "util";
import * as fsp from "fs/promises";
import * as timers from "timers/promises";
Expand Down Expand Up @@ -282,10 +283,27 @@ export default class LogtalkTerminal {
LogtalkTerminal.sendString(goals);
}

public static async genDocumentation(uri: Uri) {
public static async genDocumentation(uri: Uri, documentationLinter: LogtalkDocumentationLinter) {
if (typeof uri === 'undefined') {
uri = window.activeTextEditor.document.uri;
}
let textDocument = null;
let logtalkHome: string = '';
let logtalkUser: string = '';
// Check for Configurations
let section = workspace.getConfiguration("logtalk");
if (section) {
logtalkHome = jsesc(section.get<string>("home.path", "logtalk"));
logtalkUser = jsesc(section.get<string>("user.path", "logtalk"));
} else {
throw new Error("configuration settings error: logtalk");
}
// Open the Text Document
await workspace.openTextDocument(uri).then((document: TextDocument) => { textDocument = document });
// Clear the Scratch Message File
let compilerMessagesFile = `${logtalkUser}/scratch/.messages`;
await fsp.rm(`${compilerMessagesFile}`, { force: true });
// Create the Terminal
LogtalkTerminal.createLogtalkTerm();
const dir0: string = LogtalkTerminal.ensureDir(uri);
const loader0 = path.join(dir0, "loader");
Expand All @@ -297,6 +315,17 @@ export default class LogtalkTerminal {
const marker = path.join(dir0, ".vscode_xml_files_done");
await LogtalkTerminal.waitForFile(marker);
await fsp.rm(marker, { force: true });
if(fs.existsSync(`${compilerMessagesFile}`)) {
const lines = fs.readFileSync(`${compilerMessagesFile}`).toString().split(/\r?\n/);
let message = '';
for (const line of lines) {
message = message + line + '\n';
if(line == '* ' || line == '! ') {
documentationLinter.lint(textDocument, message);
message = '';
}
}
}
LogtalkTerminal.spawnScript4(
xmlDir0,
["documentation", "logtalk.documentation.script", LogtalkTerminal._docExec],
Expand Down

0 comments on commit 46c3a57

Please sign in to comment.