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

Diagram

a b c d modport smc_client_tts modport smc_pk modport smc_rt e g wire h ['A:0] macro_ex1 ['BCD:0] macro_ex2 ['XYZ_OP:0] macro_ex3 [7:0] i wire [9:0] k f wire [9:0] l -

Description

This is an entity description. also in multi-lines

Example of description beakline

Example of Wavedrom image:


pclkPclknclkNclkclk0clk1clk2clk3clk4

Example of bitfield:


06711121415192031opcoderdfunc3rs1imm[11:0]OP-IMMdestADDISLTISLTIUANDIORIXORIsrcI-immediate[11:0]

Example of multiline code snipet:

int* versions = 0x0080000000 ;
int* major = 0x0090000000 ;
int* minor = 0x00A0000000 ;
int* patch = 0x00B0000000 ;
print_version();

Example of multiline code snipet:

function sum(a : integer := 0; b : integer := 0)
return integer is
variable result : integer;
begin
result <= a + b;
return result;
end function;

Generics

+

Description

This is an entity description. also in multi-lines

Example of description beakline

Example of unordered list:

Example of Wavedrom image:


pclkPclknclkNclkclk0clk1clk2clk3clk4

Example of bitfield:


06711121415192031opcoderdfunc3rs1imm[11:0]OP-IMMdestADDISLTISLTIUANDIORIXORIsrcI-immediate[11:0]

Example of multiline code snipet:

int* versions = 0x0080000000 ;
int* major = 0x0090000000 ;
int* minor = 0x00A0000000 ;
int* patch = 0x00B0000000 ;
print_version();

Example of multiline code snipet:

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: -![alt text](wavedrom_fpUS0.svg "title") +![alt text](wavedrom_fgD90.svg "title") @@ -27,7 +35,7 @@ Example of bitfield: -![alt text](wavedrom_jn9w1.svg "title") +![alt text](wavedrom_D2eS1.svg "title") 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

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 -

Description

This is an entity description 5 multiline.

Example of multiline code snipet:

int* versions = 0x0080000000 ;
int* major = 0x0090000000 ;
int* minor = 0x00A0000000 ;
int* patch = 0x00B0000000 ;
print_version();

Example of multiline code snipet:

function sum(a : integer := 0; b : integer := 0)
return integer is
variable result : integer;
begin
result <= a + b;
return result;
end function;

Example of description beakline

Example of Wavedrom

image:


pclkPclknclkNclkclk0clk1clk2clk3clk4

Example of bitfield:


06711121415192031opcoderdfunc3rs1imm[11:0]OP-IMMdestADDISLTISLTIUANDIORIXORIsrcI-immediate[11:0]

Generics

+

Description

This is an entity description 5 multiline.

Example of unordered list:

Example of multiline code snipet:

int* versions = 0x0080000000 ;
int* major = 0x0090000000 ;
int* minor = 0x00A0000000 ;
int* patch = 0x00B0000000 ;
print_version();

Example of multiline code snipet:

function sum(a : integer := 0; b : integer := 0)
return integer is
variable result : integer;
begin
result <= a + b;
return result;
end function;

Example of description beakline

Example of Wavedrom

image:


pclkPclknclkNclkclk0clk1clk2clk3clk4

Example of bitfield:


06711121415192031opcoderdfunc3rs1imm[11:0]OP-IMMdestADDISLTISLTIUANDIORIXORIsrcI-immediate[11:0]

Generics

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