Skip to content

Commit 96a6fec

Browse files
authored
Show All Diagnostics Button (#29)
1 parent aa4c1a0 commit 96a6fec

8 files changed

Lines changed: 99 additions & 30 deletions

File tree

client/src/extension.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let logger: LiquidJavaLogger;
1818
let statusBarItem: vscode.StatusBarItem;
1919
let currentDiagnostics: LJDiagnostic[];
2020
let webviewProvider: LiquidJavaWebviewProvider;
21-
let currentFilePath: string | undefined;
21+
let currentFile: string | undefined;
2222

2323
/**
2424
* Activates the LiquidJava extension
@@ -35,7 +35,8 @@ export async function activate(context: vscode.ExtensionContext) {
3535

3636
const activeEditor = vscode.window.activeTextEditor;
3737
if (activeEditor && activeEditor.document.languageId === "java") {
38-
currentFilePath = activeEditor.document.uri.fsPath;
38+
currentFile = activeEditor.document.uri.fsPath;
39+
webviewProvider?.sendMessage({ type: "file", file: currentFile });
3940
}
4041
await applyItalicOverlay();
4142

@@ -132,16 +133,17 @@ function initWebview(context: vscode.ExtensionContext) {
132133
webviewProvider.onDidReceiveMessage(message => {
133134
console.log("received message", message);
134135
if (message.type === "ready") {
135-
webviewProvider.sendMessage({ type: "diagnostics", diagnostics: currentDiagnostics, file: currentFilePath });
136+
webviewProvider.sendMessage({ type: "file", file: currentFile });
137+
webviewProvider.sendMessage({ type: "diagnostics", diagnostics: currentDiagnostics });
136138
}
137139
})
138140
);
139141
// listen for active text editor changes
140142
context.subscriptions.push(
141143
vscode.window.onDidChangeActiveTextEditor(editor => {
142144
if (editor && editor.document.languageId === "java") {
143-
currentFilePath = editor.document.uri.fsPath;
144-
webviewProvider?.sendMessage({ type: "diagnostics", diagnostics: currentDiagnostics, file: currentFilePath });
145+
currentFile = editor.document.uri.fsPath;
146+
webviewProvider?.sendMessage({ type: "file", file: currentFile });
145147
}
146148
})
147149
);
@@ -330,6 +332,6 @@ function handleLJDiagnostics(diagnostics: LJDiagnostic[]) {
330332
} else {
331333
updateStatusBar("passed");
332334
}
333-
webviewProvider?.sendMessage({ type: "diagnostics", diagnostics, file: currentFilePath });
335+
webviewProvider?.sendMessage({ type: "diagnostics", diagnostics });
334336
currentDiagnostics = diagnostics;
335337
}

client/src/types/diagnostics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export type LJDiagnostic = LJError | LJWarning;
2626

2727
export type LJError = CustomError | IllegalConstructorTransitionError |
2828
InvalidRefinementError | NotFoundError | RefinementError | StateConflictError |
29-
StateRefinementError | SyntaxError;
29+
StateRefinementError | SyntaxError | ArgumentMismatchError;
3030

3131
export type LJWarning = CustomWarning | ExternalClassNotFoundWarning | ExternalMethodNotFoundWarning;
3232

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import { renderShowAllButton } from "./diagnostics/show-all-button";
12

2-
export function getCorrectView(): string {
3+
export function getCorrectView(showAllDiagnostics: boolean): string {
34
return /*html*/`
45
<div>
5-
<h2>Passed Verification</h2>
6-
<p>No errors were found by the LiquidJava verifier.</p>
6+
<div class="header">
7+
<h2>Passed Verification</h2>
8+
${renderShowAllButton(showAllDiagnostics)}
9+
</div>
10+
<p class="info">No errors were found by the LiquidJava verifier.</p>
711
</div>
812
`;
913
}

client/src/webview/renderers/diagnostics/errors.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,27 @@ import {
1111

1212
} from "../../../types";
1313
import { renderDerivationNode } from "./derivation-nodes";
14+
import { renderShowAllButton } from "./show-all-button";
1415

15-
export function getErrorsView(errors: LJError[], totalErrors: number): string {
16+
export function getErrorsView(errors: LJError[], showAll: boolean, currentFile: string | undefined): string {
17+
const displayDiagnostics = showAll ? errors : errors.filter(error => error.file && error.file?.toLowerCase() === currentFile?.toLowerCase());
18+
const hiddenCount = errors.length - displayDiagnostics.length;
1619
return /*html*/`
1720
<div>
18-
<h2>Failed Verification</h2>
19-
<p>${totalErrors} error${totalErrors > 1 ? 's were' : ' was'} found by the LiquidJava verifier.</p>
21+
<div class="header">
22+
<h2>Failed Verification</h2>
23+
${renderShowAllButton(showAll)}
24+
</div>
25+
<p class="info">${`${errors.length} error${errors.length !== 1 ? 's were' : ' was'} found by the LiquidJava verifier.`}</p>
2026
<div class="content">
2127
<ul>
22-
${errors.map((error) => /*html*/`
28+
${displayDiagnostics.map((error) => /*html*/`
2329
<li class="diagnostic-item error-item">
2430
${renderError(error)}
2531
</li>
2632
`).join("")}
2733
</ul>
34+
${hiddenCount > 0 ? `<p class="more-indicator">(+${hiddenCount} error${hiddenCount !== 1 ? 's' : ''})</p>` : ''}
2835
</div>
2936
</div>
3037
`;
@@ -64,7 +71,15 @@ export function renderError(error: LJError): string {
6471
const e = error as SyntaxError;
6572
return `${header}${renderSection('Refinement', `<pre>"${e.refinement}"</pre>`)}${location}`;
6673
}
74+
case 'argument-mismatch-error': {
75+
const e = error as ArgumentMismatchError;
76+
return `${header}${renderSection('Refinement', `<pre>"${e.refinement}"</pre>`)}${location}`;
77+
}
6778
default:
6879
return `${header}${location}`;
6980
}
7081
}
82+
function renderToggleButton(showAll: boolean) {
83+
throw new Error("Function not implemented.");
84+
}
85+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
export function renderShowAllButton(showAll: boolean): string {
3+
return /*html*/`
4+
<button class="show-all-button" title="Toggle filter diagnostics by current file">
5+
${showAll ? 'Show in File' : 'Show All'}
6+
</button>
7+
`;
8+
}

client/src/webview/renderers/diagnostics/warnings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { ExternalClassNotFoundWarning, ExternalMethodNotFoundWarning, LJWarning } from "../../../types";
22
import { renderHeader, renderLocation, renderSection } from "./utils";
33

4-
export function getWarningsView(warnings: LJWarning[]): string {
4+
export function getWarningsView(warnings: LJWarning[], showAllDiagnostics: boolean, currentFile: string | undefined): string {
55
return /*html*/`
66
<div>
77
<div class="content">
88
<ul>
9-
${warnings.map((warning) => /*html*/`
9+
${warnings.filter(warning => showAllDiagnostics || warning.file === currentFile).map((warning) => /*html*/`
1010
<li class="diagnostic-item warning-item">
1111
${renderWarning(warning)}
1212
</li>

client/src/webview/script.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ export function getScript(vscode: any, document: any, window: any) {
1515
const root = document.getElementById('root');
1616
let fileErrors: LJError[] = [];
1717
let fileWarnings: LJWarning[] = [];
18-
let totalErrors = 0;
19-
let totalWarnings = 0;
18+
let showAllDiagnostics = false;
19+
let currentFile: string | undefined;
2020

2121
// initial state
2222
root.innerHTML = getLoadingView();
@@ -61,29 +61,38 @@ export function getScript(vscode: any, document: any, window: any) {
6161
if (handleDerivationResetClick(target)) {
6262
updateView();
6363
}
64+
return;
65+
}
66+
67+
// toggle show all diagnostics
68+
if (target.classList.contains('show-all-button')) {
69+
e.stopPropagation();
70+
showAllDiagnostics = !showAllDiagnostics;
71+
updateView();
72+
return;
6473
}
6574
});
6675

6776
window.addEventListener('message', event => {
6877
const msg = event.data;
6978
if (msg.type === 'diagnostics') {
7079
const diagnostics = msg.diagnostics as LJDiagnostic[];
71-
const errors = diagnostics.filter((diag: LJDiagnostic) => diag.category === 'error') as LJError[];
72-
const warnings = diagnostics.filter((diag: LJDiagnostic) => diag.category === 'warning') as LJWarning[];
73-
74-
totalErrors = errors.length;
75-
totalWarnings = warnings.length;
76-
77-
fileErrors = errors.filter(error => error.file === msg.file || error.file === undefined);
78-
fileWarnings = warnings.filter(warning => warning.file === msg.file || warning.file === undefined);
80+
const errors = diagnostics.filter((d: LJDiagnostic) => d.category === 'error') as LJError[];
81+
const warnings = diagnostics.filter((d: LJDiagnostic) => d.category === 'warning') as LJWarning[];
7982

83+
fileErrors = errors;
84+
fileWarnings = warnings;
85+
8086
updateView();
87+
} else if (msg.type === 'file') {
88+
currentFile = msg.file;
89+
if (!showAllDiagnostics) updateView();
8190
}
8291
});
8392

8493
function updateView() {
85-
let mainView = totalErrors > 0 ? getErrorsView(fileErrors, totalErrors) : getCorrectView();
86-
let warningsView = totalWarnings > 0 ? getWarningsView(fileWarnings) : '';
94+
let mainView = fileErrors.length > 0 ? getErrorsView(fileErrors, showAllDiagnostics, currentFile) : getCorrectView(showAllDiagnostics);
95+
let warningsView = fileWarnings.length > 0 ? getWarningsView(fileWarnings, showAllDiagnostics, currentFile) : '';
8796
root.innerHTML = mainView + warningsView;
8897
}
8998
}

client/src/webview/styles.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ export function getStyles(): string {
88
body {
99
padding: 1rem;
1010
font-family: var(--vscode-font-family);
11+
overflow-y: scroll;
1112
}
1213
h2 {
1314
font-weight: bold;
14-
margin: 0 0 1rem 0;
15+
margin: 0;
1516
}
1617
p {
1718
word-wrap: break-word;
@@ -45,6 +46,11 @@ export function getStyles(): string {
4546
overflow: visible;
4647
position: relative;
4748
}
49+
.header {
50+
display: flex;
51+
justify-content: space-between;
52+
align-items: start;
53+
}
4854
.diagnostic-header {
4955
margin: 1rem 0;
5056
}
@@ -56,7 +62,7 @@ export function getStyles(): string {
5662
.diagnostic-item {
5763
background-color: var(--vscode-textBlockQuote-background);
5864
padding: 1rem;
59-
margin: 1rem 0;
65+
margin-bottom: 1rem;
6066
border-radius: 4px;
6167
}
6268
.diagnostic-item h3 {
@@ -131,10 +137,26 @@ export function getStyles(): string {
131137
}
132138
.reset-btn:hover {
133139
font-weight: bold;
140+
background-color: transparent;
134141
}
135142
.reset-btn:disabled {
136143
opacity: 0.5;
137144
}
145+
button {
146+
padding: 0.2rem 0.6rem;
147+
background-color: var(--vscode-button-background);
148+
color: var(--vscode-button-foreground);
149+
border: 1px solid var(--vscode-button-border);
150+
border-radius: 4px;
151+
cursor: pointer;
152+
font-family: var(--vscode-font-family);
153+
font-size: 0.9rem;
154+
transition: background-color 0.2s;
155+
}
156+
button:hover {
157+
background-color: var(--vscode-button-hoverBackground);
158+
}
159+
138160
.tooltip:hover::after {
139161
content: attr(data-tooltip);
140162
position: absolute;
@@ -164,5 +186,14 @@ export function getStyles(): string {
164186
z-index: 1000;
165187
pointer-events: none;
166188
}
189+
.more-indicator {
190+
text-align: center;
191+
font-size: 0.8rem;
192+
opacity: 0.6;
193+
margin-bottom: 1rem;
194+
}
195+
.info {
196+
margin: 1rem 0;
197+
}
167198
`;
168199
}

0 commit comments

Comments
 (0)