diff --git a/src/colibri/documenter/utils.ts b/src/colibri/documenter/utils.ts
index 301176c8..efdb1e28 100644
--- a/src/colibri/documenter/utils.ts
+++ b/src/colibri/documenter/utils.ts
@@ -22,11 +22,94 @@ import * as translator_lib from "./translator";
import * as md from "./markdown_table";
const showdown = require('showdown');
+/**
+ * Detect and convert unordered list patterns in comments to markdown format
+ * @param description The description text to process
+ * @returns The description with unordered lists converted to markdown format
+ */
+export function convert_unordered_lists_to_markdown(description: string): string {
+ if (!description) {
+ return "";
+ }
+
+ const lines = description.split('\n');
+ const result: string[] = [];
+ let i = 0;
+
+ while (i < lines.length) {
+ const line = lines[i];
+ const trimmedLine = line.trim();
+
+ // Check if current line starts a list (- or * followed by space)
+ const listMatch = trimmedLine.match(/^[*-]\s+(.+)$/);
+ if (listMatch) {
+ // Found start of a list, collect all list items
+ const listItems: string[] = [];
+ let j = i; // Store start position for backtracking
+
+ while (i < lines.length) {
+ const currentLine = lines[i];
+ const currentTrimmed = currentLine.trim();
+ const currentListMatch = currentTrimmed.match(/^[*-]\s+(.+)$/);
+
+ if (currentListMatch) {
+ // This is a list item
+ listItems.push(currentListMatch[1]);
+ i++;
+ } else if (currentTrimmed === '') {
+ // Empty line ends the list
+ break;
+ } else if (listItems.length > 0 && /^\s+/.test(currentLine) && currentTrimmed !== '') {
+ // Continuation of previous list item (indented line with content)
+ listItems[listItems.length - 1] += ' ' + currentTrimmed;
+ i++;
+ } else {
+ // Non-list line, end the list
+ break;
+ }
+ }
+
+ // Only convert to list if we have at least 2 items
+ if (listItems.length >= 2) {
+ // Add empty line before list if needed
+ if (result.length > 0 && result[result.length - 1].trim() !== '') {
+ result.push('');
+ }
+
+ // Add list items in markdown format
+ for (const item of listItems) {
+ result.push(`* ${item}`);
+ }
+
+ // Add empty line after list if there's more content
+ if (i < lines.length) {
+ result.push('');
+ }
+ } else {
+ // Not enough items for a list, treat as regular lines by rewinding
+ i = j;
+ result.push(lines[i]);
+ i++;
+ }
+ } else {
+ // Regular line, add as-is
+ result.push(lines[i]);
+ i++;
+ }
+ }
+
+ return result.join('\n');
+}
+
export function normalize_description(description: string): string {
if(!description){
return "";
}
- let desc_inst = description.replace(/\n\s*\n/g, ' ');
+
+ // Convert unordered lists to markdown format first
+ let desc_inst = convert_unordered_lists_to_markdown(description);
+
+ desc_inst = desc_inst.replace(/\n\s*\n/g, ' ');
desc_inst = desc_inst.replace(/\n/g, ' ');
desc_inst = desc_inst.replace(/ /g, ' ');
return desc_inst;
@@ -36,7 +119,11 @@ export function normalize_description_markdown(description: string): string {
if(!description){
return "";
}
- const sections = description.split(/(```[\s\S]*?```)/);
+
+ // Convert unordered lists to markdown format first
+ let processed_description = convert_unordered_lists_to_markdown(description);
+
+ const sections = processed_description.split(/(```[\s\S]*?```)/);
for (let i = 0; i < sections.length; i++) {
if (!sections[i].startsWith('```')) {
diff --git a/tests/documenter/complete/entity.verilogSource b/tests/documenter/complete/entity.verilogSource
index 2d57193b..48cffbe8 100644
--- a/tests/documenter/complete/entity.verilogSource
+++ b/tests/documenter/complete/entity.verilogSource
@@ -6,6 +6,12 @@
//!
//! Example of description beakline
//!
+//! Example of unordered list:
+//! * Normal operation mode
+//! * Low power mode
+//! * Debug mode
+//! * Test mode
+//!
//! Example of Wavedrom
//! image:
//! { signal: [
diff --git a/tests/documenter/complete/entity.vhdlSource b/tests/documenter/complete/entity.vhdlSource
index b6cca787..9e338372 100644
--- a/tests/documenter/complete/entity.vhdlSource
+++ b/tests/documenter/complete/entity.vhdlSource
@@ -7,6 +7,11 @@ use ieee.std_logic_1164.all;
--! @version 1.0.1
--! @brief Some description can be added here
--!
+--! Example of unordered list:
+--! * Normal operation mode
+--! * Low power mode
+--! * Debug mode
+--! * Test mode
--!
--! Example of multiline code snipet:
--! ``` C
diff --git a/tests/documenter/complete/expected/entity_verilogSource_html/output.html b/tests/documenter/complete/expected/entity_verilogSource_html/output.html
index db3ace7d..7980fbd9 100644
--- a/tests/documenter/complete/expected/entity_verilogSource_html/output.html
+++ b/tests/documenter/complete/expected/entity_verilogSource_html/output.html
@@ -1101,7 +1101,7 @@
Entity: test_entity_name
Version: 1.0.1
Brief: Some description can be added here
Diagram
-
Description
This is an entity description. also in multi-lines
function sum(a : integer := 0; b : integer := 0) return integer is variable result : integer; begin result <= a + b; return result; end function;
Generics
diff --git a/tests/documenter/complete/expected/entity_verilogSource_markdown/output.markdown b/tests/documenter/complete/expected/entity_verilogSource_markdown/output.markdown
index 569902c8..362b070e 100644
--- a/tests/documenter/complete/expected/entity_verilogSource_markdown/output.markdown
+++ b/tests/documenter/complete/expected/entity_verilogSource_markdown/output.markdown
@@ -14,12 +14,20 @@ also in multi-lines
Example of description beakline
+Example of unordered list:
+
+* Normal operation mode
+* Low power mode
+* Debug mode
+* Test mode
+
+
Example of Wavedrom
image:
-
+
@@ -27,7 +35,7 @@ Example of bitfield:
-
+
diff --git a/tests/documenter/complete/expected/entity_vhdlSource_html/output.html b/tests/documenter/complete/expected/entity_vhdlSource_html/output.html
index 33917a5f..06aa5d2a 100644
--- a/tests/documenter/complete/expected/entity_vhdlSource_html/output.html
+++ b/tests/documenter/complete/expected/entity_vhdlSource_html/output.html
@@ -1101,7 +1101,7 @@
Entity: test_entity_name
Version: 1.0.1
Brief: Some description can be added here
Diagram
integer a std_logic b std_logic_vector(1 downto 0) c std_logic_vector(1 downto 0) d std_logic e std_logic ee std_logic_vector(31 downto 0) h std_logic_vector(31 downto 0) i std_logic r std_logic j std_logic m virtual_bus v_bus_2 virtual_bus video_in_axi_stream std_logic video_out_tready std_logic q std_logic s std_logic f std_logic ff std_logic g std_logic l std_logic_vector(23 downto 0) video_out_tdata std_logic video_out_tlast std_logic_vector(0 downto 0) video_out_tuser std_logic video_out_tvalid virtual_bus SPI
-
diff --git a/tests/documenter/complete/expected/entity_vhdlSource_markdown/output.markdown b/tests/documenter/complete/expected/entity_vhdlSource_markdown/output.markdown
index cd7ec117..03a0a44c 100644
--- a/tests/documenter/complete/expected/entity_vhdlSource_markdown/output.markdown
+++ b/tests/documenter/complete/expected/entity_vhdlSource_markdown/output.markdown
@@ -12,6 +12,13 @@
This is an entity description 5
multiline.
+Example of unordered list:
+
+* Normal operation mode
+* Low power mode
+* Debug mode
+* Test mode
+
Example of multiline code snipet:
diff --git a/tests/documenter/unordered_list.spec.ts b/tests/documenter/unordered_list.spec.ts
new file mode 100644
index 00000000..658c38f9
--- /dev/null
+++ b/tests/documenter/unordered_list.spec.ts
@@ -0,0 +1,161 @@
+// Test cases for the unordered list feature
+import { convert_unordered_lists_to_markdown } from "../../src/colibri/documenter/utils";
+
+describe('Unordered List Conversion Tests', () => {
+
+ test('Basic asterisk list conversion', () => {
+ const input = `This is a description with a list:
+* First item
+* Second item
+* Third item
+End of description.`;
+
+ const expected = `This is a description with a list:
+
+* First item
+* Second item
+* Third item
+
+End of description.`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+
+ test('Basic dash list conversion', () => {
+ const input = `Configuration options:
+- Option A
+- Option B
+- Option C`;
+
+ const expected = `Configuration options:
+
+* Option A
+* Option B
+* Option C`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+
+ test('Mixed list markers should work', () => {
+ const input = `Mixed list:
+* Item with asterisk
+- Item with dash
+* Another asterisk item`;
+
+ const expected = `Mixed list:
+
+* Item with asterisk
+* Item with dash
+* Another asterisk item`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+
+ test('Single item should not be converted to list', () => {
+ const input = `Single item:
+* Only one item
+Regular text continues.`;
+
+ const expected = `Single item:
+* Only one item
+Regular text continues.`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+
+ test('Multi-line list items', () => {
+ const input = `Complex list:
+* First item with continuation
+ on the next line
+* Second item also spans
+ multiple lines
+* Third item`;
+
+ const expected = `Complex list:
+
+* First item with continuation on the next line
+* Second item also spans multiple lines
+* Third item`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+
+ test('Empty lines should terminate list', () => {
+ const input = `List with break:
+* First item
+* Second item
+
+* This starts a new list
+* Fourth item`;
+
+ const expected = `List with break:
+
+* First item
+* Second item
+
+
+* This starts a new list
+* Fourth item`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+
+ test('No conversion for non-list content', () => {
+ const input = `Regular description without lists.
+This is just normal text.
+No special formatting here.`;
+
+ const expected = `Regular description without lists.
+This is just normal text.
+No special formatting here.`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+
+ test('Empty or null input', () => {
+ expect(convert_unordered_lists_to_markdown("")).toBe("");
+ expect(convert_unordered_lists_to_markdown(null as any)).toBe("");
+ expect(convert_unordered_lists_to_markdown(undefined as any)).toBe("");
+ });
+
+ test('List at beginning of text', () => {
+ const input = `* First item
+* Second item
+* Third item
+Regular text follows.`;
+
+ const expected = `* First item
+* Second item
+* Third item
+
+Regular text follows.`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+
+ test('List at end of text', () => {
+ const input = `Description text here.
+Available options:
+* Option 1
+* Option 2
+* Option 3`;
+
+ const expected = `Description text here.
+Available options:
+
+* Option 1
+* Option 2
+* Option 3`;
+
+ const result = convert_unordered_lists_to_markdown(input);
+ expect(result).toBe(expected);
+ });
+});
\ No newline at end of file