Skip to content

Commit 23f58b9

Browse files
feat: add markdown output mode to mat-cli (#10)
1 parent 18cdb06 commit 23f58b9

29 files changed

Lines changed: 1468 additions & 153 deletions

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ If you are looking for the full Eclipse MAT desktop/RCP distribution, official p
1919
## Features
2020

2121
- Analyze Java heap dumps from the command line
22-
- Text and JSON output modes
22+
- Text, Markdown, and JSON output modes
2323
- Built-in commands such as `summary`, `threads`, `objects`, `instances`, `inspect-object`, `biggest-objects`, `path2gc`, `oql`, and `query`
2424
- Standalone zip releases and Homebrew installation
2525
- Built on top of Eclipse MAT internals and query engine
@@ -99,6 +99,7 @@ Useful discovery commands:
9999

100100
- `mat-cli <command> --help`
101101
- `mat-cli describe <command>`
102+
- `mat-cli describe <command> --format markdown`
102103
- `mat-cli schema <command> --format json`
103104
- `mat-cli list-queries --format json`
104105
- `mat-cli describe-query <query-id> --format json`

features/org.eclipse.mat.cli.feature/rootfiles/completion/bash/mat-cli

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ _mat_cli_option_kind_global() {
2121
printf '%s\n' 'none'
2222
;;
2323
--format)
24-
printf '%s\n' 'enum:text json'
24+
printf '%s\n' 'enum:text json markdown'
2525
;;
2626
esac
2727
}
@@ -32,7 +32,7 @@ _mat_cli_option_kind_for_command() {
3232
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
3333
;;
3434
summary:--format)
35-
printf '%s\n' 'enum:text json'
35+
printf '%s\n' 'enum:text json markdown'
3636
;;
3737
threads:--limit)
3838
printf '%s\n' 'free-text'
@@ -41,7 +41,7 @@ _mat_cli_option_kind_for_command() {
4141
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
4242
;;
4343
threads:--format)
44-
printf '%s\n' 'enum:text json'
44+
printf '%s\n' 'enum:text json markdown'
4545
;;
4646
objects:--by)
4747
printf '%s\n' 'enum:class package class-loader'
@@ -59,7 +59,7 @@ _mat_cli_option_kind_for_command() {
5959
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
6060
;;
6161
objects:--format)
62-
printf '%s\n' 'enum:text json'
62+
printf '%s\n' 'enum:text json markdown'
6363
;;
6464
objects:--dump)
6565
printf '%s\n' 'none'
@@ -83,7 +83,7 @@ _mat_cli_option_kind_for_command() {
8383
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
8484
;;
8585
instances:--format)
86-
printf '%s\n' 'enum:text json'
86+
printf '%s\n' 'enum:text json markdown'
8787
;;
8888
instances:--dump)
8989
printf '%s\n' 'none'
@@ -113,7 +113,7 @@ _mat_cli_option_kind_for_command() {
113113
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
114114
;;
115115
inspect-object:--format)
116-
printf '%s\n' 'enum:text json'
116+
printf '%s\n' 'enum:text json markdown'
117117
;;
118118
biggest-objects:--limit)
119119
printf '%s\n' 'free-text'
@@ -125,7 +125,7 @@ _mat_cli_option_kind_for_command() {
125125
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
126126
;;
127127
biggest-objects:--format)
128-
printf '%s\n' 'enum:text json'
128+
printf '%s\n' 'enum:text json markdown'
129129
;;
130130
biggest-objects:--dump)
131131
printf '%s\n' 'none'
@@ -146,7 +146,7 @@ _mat_cli_option_kind_for_command() {
146146
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
147147
;;
148148
path2gc:--format)
149-
printf '%s\n' 'enum:text json'
149+
printf '%s\n' 'enum:text json markdown'
150150
;;
151151
oql:--query)
152152
printf '%s\n' 'free-text'
@@ -170,7 +170,7 @@ _mat_cli_option_kind_for_command() {
170170
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
171171
;;
172172
oql:--format)
173-
printf '%s\n' 'enum:text json'
173+
printf '%s\n' 'enum:text json markdown'
174174
;;
175175
query:--command)
176176
printf '%s\n' 'free-text'
@@ -194,22 +194,22 @@ _mat_cli_option_kind_for_command() {
194194
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
195195
;;
196196
query:--format)
197-
printf '%s\n' 'enum:text json'
197+
printf '%s\n' 'enum:text json markdown'
198198
;;
199199
describe:--format)
200-
printf '%s\n' 'enum:text json'
200+
printf '%s\n' 'enum:text json markdown'
201201
;;
202202
schema:--format)
203-
printf '%s\n' 'enum:text json'
203+
printf '%s\n' 'enum:text json markdown'
204204
;;
205205
list-queries:--format)
206-
printf '%s\n' 'enum:text json'
206+
printf '%s\n' 'enum:text json markdown'
207207
;;
208208
describe-query:--format)
209-
printf '%s\n' 'enum:text json'
209+
printf '%s\n' 'enum:text json markdown'
210210
;;
211211
completion:--format)
212-
printf '%s\n' 'enum:text json'
212+
printf '%s\n' 'enum:text json markdown'
213213
;;
214214
esac
215215
}

features/org.eclipse.mat.cli.feature/rootfiles/completion/zsh/_mat-cli

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ _mat_cli_option_kind_global() {
2222
printf '%s\n' 'none'
2323
;;
2424
--format)
25-
printf '%s\n' 'enum:text json'
25+
printf '%s\n' 'enum:text json markdown'
2626
;;
2727
esac
2828
}
@@ -33,7 +33,7 @@ _mat_cli_option_kind_for_command() {
3333
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
3434
;;
3535
summary:--format)
36-
printf '%s\n' 'enum:text json'
36+
printf '%s\n' 'enum:text json markdown'
3737
;;
3838
threads:--limit)
3939
printf '%s\n' 'free-text'
@@ -42,7 +42,7 @@ _mat_cli_option_kind_for_command() {
4242
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
4343
;;
4444
threads:--format)
45-
printf '%s\n' 'enum:text json'
45+
printf '%s\n' 'enum:text json markdown'
4646
;;
4747
objects:--by)
4848
printf '%s\n' 'enum:class package class-loader'
@@ -60,7 +60,7 @@ _mat_cli_option_kind_for_command() {
6060
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
6161
;;
6262
objects:--format)
63-
printf '%s\n' 'enum:text json'
63+
printf '%s\n' 'enum:text json markdown'
6464
;;
6565
objects:--dump)
6666
printf '%s\n' 'none'
@@ -84,7 +84,7 @@ _mat_cli_option_kind_for_command() {
8484
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
8585
;;
8686
instances:--format)
87-
printf '%s\n' 'enum:text json'
87+
printf '%s\n' 'enum:text json markdown'
8888
;;
8989
instances:--dump)
9090
printf '%s\n' 'none'
@@ -114,7 +114,7 @@ _mat_cli_option_kind_for_command() {
114114
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
115115
;;
116116
inspect-object:--format)
117-
printf '%s\n' 'enum:text json'
117+
printf '%s\n' 'enum:text json markdown'
118118
;;
119119
biggest-objects:--limit)
120120
printf '%s\n' 'free-text'
@@ -126,7 +126,7 @@ _mat_cli_option_kind_for_command() {
126126
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
127127
;;
128128
biggest-objects:--format)
129-
printf '%s\n' 'enum:text json'
129+
printf '%s\n' 'enum:text json markdown'
130130
;;
131131
biggest-objects:--dump)
132132
printf '%s\n' 'none'
@@ -147,7 +147,7 @@ _mat_cli_option_kind_for_command() {
147147
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
148148
;;
149149
path2gc:--format)
150-
printf '%s\n' 'enum:text json'
150+
printf '%s\n' 'enum:text json markdown'
151151
;;
152152
oql:--query)
153153
printf '%s\n' 'free-text'
@@ -171,7 +171,7 @@ _mat_cli_option_kind_for_command() {
171171
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
172172
;;
173173
oql:--format)
174-
printf '%s\n' 'enum:text json'
174+
printf '%s\n' 'enum:text json markdown'
175175
;;
176176
query:--command)
177177
printf '%s\n' 'free-text'
@@ -195,22 +195,22 @@ _mat_cli_option_kind_for_command() {
195195
printf '%s\n' 'enum:bytes kilobytes megabytes gigabytes smart'
196196
;;
197197
query:--format)
198-
printf '%s\n' 'enum:text json'
198+
printf '%s\n' 'enum:text json markdown'
199199
;;
200200
describe:--format)
201-
printf '%s\n' 'enum:text json'
201+
printf '%s\n' 'enum:text json markdown'
202202
;;
203203
schema:--format)
204-
printf '%s\n' 'enum:text json'
204+
printf '%s\n' 'enum:text json markdown'
205205
;;
206206
list-queries:--format)
207-
printf '%s\n' 'enum:text json'
207+
printf '%s\n' 'enum:text json markdown'
208208
;;
209209
describe-query:--format)
210-
printf '%s\n' 'enum:text json'
210+
printf '%s\n' 'enum:text json markdown'
211211
;;
212212
completion:--format)
213-
printf '%s\n' 'enum:text json'
213+
printf '%s\n' 'enum:text json markdown'
214214
;;
215215
esac
216216
}

plugins/org.eclipse.mat.cli/src/org/eclipse/mat/cli/internal/CliApplication.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public Object start(IApplicationContext context) throws Exception
3939
CliArguments.OutputFormat requestedFormat = parser.detectFormat(args);
4040
try
4141
{
42-
if (requestedFormat == CliArguments.OutputFormat.JSON)
42+
if (requestedFormat == CliArguments.OutputFormat.JSON || requestedFormat == CliArguments.OutputFormat.MARKDOWN)
4343
Locale.setDefault(Locale.ENGLISH);
4444

4545
parsed = parser.parse(args);
@@ -91,8 +91,8 @@ private Object exit(int code, CliArguments parsed, CliArguments.OutputFormat req
9191
PrintStream err, PrintStream out)
9292
{
9393
CliArguments.OutputFormat format = parsed == null ? requestedFormat : parsed.getFormat();
94-
boolean json = format == CliArguments.OutputFormat.JSON;
95-
if (json)
94+
boolean structured = format == CliArguments.OutputFormat.JSON || format == CliArguments.OutputFormat.MARKDOWN;
95+
if (structured)
9696
{
9797
serializer.serializeError(parsed, format, code, error, out);
9898
}

plugins/org.eclipse.mat.cli/src/org/eclipse/mat/cli/internal/CliArguments.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,16 @@ public static ObjectsGrouping parse(String value) throws CliException
3636

3737
public enum OutputFormat
3838
{
39-
TEXT, JSON;
39+
TEXT, JSON, MARKDOWN;
4040

4141
public static OutputFormat parse(String value) throws CliException
4242
{
4343
if ("text".equalsIgnoreCase(value)) //$NON-NLS-1$
4444
return TEXT;
4545
if ("json".equalsIgnoreCase(value)) //$NON-NLS-1$
4646
return JSON;
47+
if ("markdown".equalsIgnoreCase(value)) //$NON-NLS-1$
48+
return MARKDOWN;
4749
throw CliException.usage("Unsupported format: " + value); //$NON-NLS-1$
4850
}
4951
}

plugins/org.eclipse.mat.cli/src/org/eclipse/mat/cli/internal/CliCommandCatalog.java

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ private OptionDefinition(String name, String valueHint, boolean required, String
6262
CompletionValueType completionValueType, List<String> completionCandidates)
6363
{
6464
this.name = name;
65-
this.valueHint = valueHint;
65+
this.valueHint = "--format".equals(name) ? expandFormatHint(valueHint) : valueHint; //$NON-NLS-1$
6666
this.required = required;
67-
this.description = description;
67+
this.description = "--format".equals(name) ? expandFormatDescription(description) : description; //$NON-NLS-1$
6868
this.completionValueType = completionValueType;
6969
this.completionCandidates = immutableCopy(completionCandidates);
7070
}
@@ -149,11 +149,11 @@ private CommandDefinition(CliCommand command, String summary, String usage, bool
149149
{
150150
this.command = command;
151151
this.summary = summary;
152-
this.usage = usage;
152+
this.usage = usage == null ? null : usage.replace("text|json", "text|json|markdown"); //$NON-NLS-1$ //$NON-NLS-2$
153153
this.requiresSnapshot = requiresSnapshot;
154154
this.positionalArguments = immutableCopy(positionalArguments);
155155
this.options = immutableCopy(options);
156-
this.outputs = immutableCopy(outputs);
156+
this.outputs = immutableCopy(withMarkdownOutput(outputs));
157157
this.suggestedNextCommands = immutableCopy(suggestedNextCommands);
158158
this.agentPayloadDescription = agentPayloadDescription;
159159
this.agentPayloadFields = immutableCopy(agentPayloadFields);
@@ -220,7 +220,7 @@ public String getAgentPayloadDescription()
220220
}
221221
}
222222

223-
private static final List<String> FORMAT_VALUES = immutableCopy(Arrays.asList("text", "json")); //$NON-NLS-1$ //$NON-NLS-2$
223+
private static final List<String> FORMAT_VALUES = immutableCopy(Arrays.asList("text", "json", "markdown")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
224224
private static final List<String> BYTES_DISPLAY_VALUES = immutableCopy(
225225
Arrays.asList("bytes", "kilobytes", "megabytes", "gigabytes", "smart")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
226226
private static final List<String> OBJECT_GROUPING_VALUES = immutableCopy(
@@ -233,7 +233,7 @@ public String getAgentPayloadDescription()
233233
enumOption("--format", "text|json", false, "Select text or JSON output.", FORMAT_VALUES))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
234234
private static final OptionDefinition BYTES_DISPLAY_OPTION = enumOption("--bytes-display",
235235
"bytes|kilobytes|megabytes|gigabytes|smart", false, //$NON-NLS-1$ //$NON-NLS-2$
236-
"Select byte unit rendering for text output. Defaults to smart.", BYTES_DISPLAY_VALUES); //$NON-NLS-1$
236+
"Select byte unit rendering for text and Markdown output. Defaults to smart.", BYTES_DISPLAY_VALUES); //$NON-NLS-1$
237237
private static final OptionDefinition DUMP_OPTION = flagOption("--dump",
238238
"Emit full structured values for file redirection, ignore --limit, and only honor --depth."); //$NON-NLS-1$ //$NON-NLS-2$
239239
private static final List<OptionDefinition> FORMAT_OPTION = Collections.singletonList(
@@ -567,6 +567,44 @@ private static OutputDefinition output(String format, String resultKind, String
567567
return new OutputDefinition(format, resultKind, description);
568568
}
569569

570+
private static List<OutputDefinition> withMarkdownOutput(List<OutputDefinition> outputs)
571+
{
572+
ArrayList<OutputDefinition> expanded = new ArrayList<OutputDefinition>(outputs == null ? 1 : outputs.size() + 1);
573+
boolean hasMarkdown = false;
574+
if (outputs != null)
575+
{
576+
expanded.addAll(outputs);
577+
for (OutputDefinition output : outputs)
578+
{
579+
if ("markdown".equals(output.getFormat())) //$NON-NLS-1$
580+
{
581+
hasMarkdown = true;
582+
break;
583+
}
584+
}
585+
}
586+
if (!hasMarkdown)
587+
{
588+
expanded.add(output("markdown", "markdown-document", //$NON-NLS-1$ //$NON-NLS-2$
589+
"Sectioned Markdown document for terminal and agent consumption.")); //$NON-NLS-1$
590+
}
591+
return expanded;
592+
}
593+
594+
private static String expandFormatHint(String valueHint)
595+
{
596+
if ("text|json".equals(valueHint)) //$NON-NLS-1$
597+
return "text|json|markdown"; //$NON-NLS-1$
598+
return valueHint;
599+
}
600+
601+
private static String expandFormatDescription(String description)
602+
{
603+
if ("Select text or JSON output.".equals(description)) //$NON-NLS-1$
604+
return "Select text, JSON, or Markdown output."; //$NON-NLS-1$
605+
return description;
606+
}
607+
570608
private static <T> List<T> immutableCopy(List<T> values)
571609
{
572610
if (values == null || values.isEmpty())

plugins/org.eclipse.mat.cli/src/org/eclipse/mat/cli/internal/CliCommandExecutor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.eclipse.mat.query.IResultTable;
2424
import org.eclipse.mat.query.IResultTree;
2525
import org.eclipse.mat.query.results.CompositeResult;
26+
import org.eclipse.mat.query.results.DisplayFileResult;
2627
import org.eclipse.mat.query.results.TextResult;
2728
import org.eclipse.mat.report.QuerySpec;
2829
import org.eclipse.mat.report.SectionSpec;
@@ -608,6 +609,7 @@ private void validateResult(IResult result) throws CliException
608609

609610
if (!(result instanceof TextResult || result instanceof ThreadsResult || result instanceof IResultTable
610611
|| result instanceof IResultTree || result instanceof IResultPie
612+
|| result instanceof DisplayFileResult
611613
|| result instanceof CompositeResult || result instanceof Spec))
612614
{
613615
throw CliException.unsupported("Unsupported result type: " + result.getClass().getName()); //$NON-NLS-1$

plugins/org.eclipse.mat.cli/src/org/eclipse/mat/cli/internal/CliHelp.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ public static String generalHelp()
3434
appendCommandSynopsis(help);
3535
help.append("Use 'mat-cli <command> --help' for command-specific help.\n\n"); //$NON-NLS-1$
3636
help.append("Global options:\n"); //$NON-NLS-1$
37-
help.append(" --format text|json Output format (default: text)\n"); //$NON-NLS-1$
38-
help.append(" --bytes-display MODE Byte display mode for text output: bytes|kilobytes|megabytes|gigabytes|smart (default: smart)\n"); //$NON-NLS-1$
37+
help.append(" --format text|json|markdown Output format (default: text)\n"); //$NON-NLS-1$
38+
help.append(" --bytes-display MODE Byte display mode for text and markdown output: bytes|kilobytes|megabytes|gigabytes|smart (default: smart)\n"); //$NON-NLS-1$
3939
help.append(" --limit N Maximum rows or children per level (default: 20, max: 10000)\n"); //$NON-NLS-1$
4040
help.append(" --depth N Maximum tree or section depth (default: 8, inspect-object: 3, biggest-objects: 1)\n"); //$NON-NLS-1$
4141
help.append(" --verbose Print detailed diagnostics on failure\n"); //$NON-NLS-1$

0 commit comments

Comments
 (0)