https://github.com/nich-cebolla/autohotkey-maketable
An AutoHotkey (AHK) class that converts an input string into a markdown table, html table, or pretty-aligned plain text table.
https://github.com/nich-cebolla/autohotkey-maketable
ahk autohotkey automation format html markdown string table tbl text
Last synced: 3 months ago
JSON representation
An AutoHotkey (AHK) class that converts an input string into a markdown table, html table, or pretty-aligned plain text table.
- Host: GitHub
- URL: https://github.com/nich-cebolla/autohotkey-maketable
- Owner: Nich-Cebolla
- License: mit
- Created: 2025-11-13T04:19:15.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2025-11-13T05:01:48.000Z (7 months ago)
- Last Synced: 2025-11-13T06:13:58.884Z (7 months ago)
- Topics: ahk, autohotkey, automation, format, html, markdown, string, table, tbl, text
- Language: AutoHotkey
- Homepage:
- Size: 29.3 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Table of contents
- MakeTable
- AHK forum post
- Reddit post
- Usage
- MakeTable.Prototype.GetMarkdown
- MakeTable.Prototype.GetHtml
- Changelog
- Table of contents generated by Headers2ToC.ahk
# MakeTable
An AutoHotkey (AHK) class that takes your csv-style text and converts it to one of the following:
- A Markdown-formatted table.
- An html-formatted table.
- A pretty-aligned plain text table using character count to manage table width (for use with monospace fonts).
# AHK forum post
https://www.autohotkey.com/boards/viewtopic.php?f=83&t=139518
# Reddit post
https://www.reddit.com/r/AutoHotkey/comments/1ovrn3t/maketable_a_class_that_converts_an_input_string/
# Usage
The examples in this document use the following input:
```ahk
str := "
(
calldate,src,dst,dcontext,channel
07/14/2025 02:43:44,5555557485,17,play-system-recording,PJSIP/Cox_Trunk-0000d212
07/14/2025 05:58:22,5555557984,s,ivr-6,PJSIP/Cox_Trunk-0000d213
07/14/2025 06:36:41,5555559989,s,ivr-6,PJSIP/Cox_Trunk-0000d214
07/14/2025 06:47:11,5555552202,91017,ext-queues,PJSIP/Cox_Trunk-0000d215
)"
```
Basic usage:
```ahk
#include
str := "
(
calldate,src,dst,dcontext,channel
07/14/2025 02:43:44,5555557485,17,play-system-recording,PJSIP/Cox_Trunk-0000d212
07/14/2025 05:58:22,5555557984,s,ivr-6,PJSIP/Cox_Trunk-0000d213
07/14/2025 06:36:41,5555559989,s,ivr-6,PJSIP/Cox_Trunk-0000d214
07/14/2025 06:47:11,5555552202,91017,ext-queues,PJSIP/Cox_Trunk-0000d215
)"
options := {
AddHeaderSeparator: true
, InputColumnSeparator: ','
, LinePrefix: "| "
, LineSuffix: " |"
, OutputColumnSeparator: "|"
}
tbl := MakeTable(str, options)
g := Gui()
; We need a monospaced font for the pretty-aligned text to look pretty
g.SetFont("s11 q5", "Cascadia Mono")
g.Add("Edit", "w1200 r8 -Wrap", tbl.Value)
g.Show()
; write to file
f := FileOpen(A_Temp "\MakeTable-output.md", "w")
f.Write(tbl.Value)
f.Close()
```
## Clone the repo
- Clone the repository.
```cmd
git clone https://github.com/Nich-Cebolla/AutoHotkey-MakeTable
```
- Make a copy of the cloned repository and work with the copy. This is to avoid a situation where
pulling an update breaks our scripts; by using a separate copy we can give ourselves time to review
updates before updating the active copy.
```cmd
xcopy AutoHotkey-MakeTable AutoHotkey-MakeTable-Active /I /E
```
- Add a file MakeTable.ahk to your [lib folder](https://www.autohotkey.com/docs/v2/Scripts.htm#lib).
In the file is a single statement.
```ahk
#include C:\users\you\path\to\AutoHotkey-MakeTable-Active\src\MakeTable.ahk
```
With this setup, we can use `#include ` from any other script.
## What to use as the input string
The text must be able to be divided into rows and cells using a character or regex pattern. For
example, a common csv without quoted fields is viable as an input string. However, csv with
quoted fields is not viable if the fields contain commas, because `StrSplit` will split at every
comma. You can use [ParseCsv](https://github.com/Nich-Cebolla/ParseCsv-AutoHotkey) to parse the csv
and then recreate the csv using any character that is wholly absent from the text to separate the
fields, then use that as input for `MakeTable`.
`MakeTable` accepts regex patterns to identify the boundaries between each row and each cell, so you
are not limited to only csv.
Define `Options.InputColumnSeparator` and `Options.InputRowSeparator` with the patterns. The
default values are listed below.
Pass the options object to `MakeTable.Prototype.__New` to get a `MakeTable` object.
The `MakeTable` object will have the pretty-aligned text set to property "Value". You also have
two additional methods available, `MakeTable.Prototype.GetMarkdown` and `MakeTable.Prototype.GetHtml`.
If you use a very large input (e.g. 100k+ lines), `MakeTable` will finish the job but it might take
a minute or two. Let it run and set a MsgBox to alert you when its finished.
There are various options to customize the output. Here's a few examples using various configurations.
calldate src dst dcontext channel
--------------------------------------------------------------------------------------------------------------------
07/14/2025 02:43:44 5555557485 17 play-system-recording PJSIP/Cox_Trunk-0000d-212-1080-@from-internal
--------------------------------------------------------------------------------------------------------------------
07/14/2025 05:58:22 5555557984 s ivr-6 PJSIP/Cox_Trunk-0000d-213-1080-@from-internal
--------------------------------------------------------------------------------------------------------------------
07/14/2025 06:36:41 5555559989 s ivr-6 PJSIP/Cox_Trunk-0000d-214-1080-@from-internal
--------------------------------------------------------------------------------------------------------------------
07/14/2025 06:47:11 5555552202 91017 ext-queues PJSIP/Cox_Trunk-0000d-215-1080-@from-internal
| calldate | src | dst | dcontext | channel |
| --------------------|--------------|---------|--------------------|------------------ |
| 07/14/2025 | 5555557485 | 17 | play-system-reco | PJSIP/Cox_Trunk- |
| 02:43:44 | | | rding | 0000d-212-1080-@ |
| | | | | from-internal |
| 07/14/2025 | 5555557984 | s | ivr-6 | PJSIP/Cox_Trunk- |
| 05:58:22 | | | | 0000d-213-1080-@ |
| | | | | from-internal |
| 07/14/2025 | 5555559989 | s | ivr-6 | PJSIP/Cox_Trunk- |
| 06:36:41 | | | | 0000d-214-1080-@ |
| | | | | from-internal |
| 07/14/2025 | 5555552202 | 91017 | ext-queues | PJSIP/Cox_Trunk- |
| 06:47:11 | | | | 0000d-215-1080-@ |
| | | | | from-internal |
| calldate | src | dst | dcontext | channel |
| --------------------|--------------|---------|--------------------|------------------ |
| 07/14/2025 | 5555557485 | 17 | play-system-reco | PJSIP/Cox_Trunk- |
| 02:43:44 | | | rding | 0000d-212-1080-@ |
| | | | | from-internal |
| --------------------|--------------|---------|--------------------|------------------ |
| 07/14/2025 | 5555557984 | s | ivr-6 | PJSIP/Cox_Trunk- |
| 05:58:22 | | | | 0000d-213-1080-@ |
| | | | | from-internal |
| --------------------|--------------|---------|--------------------|------------------ |
| 07/14/2025 | 5555559989 | s | ivr-6 | PJSIP/Cox_Trunk- |
| 06:36:41 | | | | 0000d-214-1080-@ |
| | | | | from-internal |
| --------------------|--------------|---------|--------------------|------------------ |
| 07/14/2025 | 5555552202 | 91017 | ext-queues | PJSIP/Cox_Trunk- |
| 06:47:11 | | | | 0000d-215-1080-@ |
| | | | | from-internal |
## Parameters
1. **{String}** - The input string.
2. **{Object}** - The options object. The options are:
- **{Boolean}** [ `Options.AddHeaderSeparator = true` ] - If true, adds a separator between
the first row and second row.
- **{String}** [ `` Options.ColumnPadding = "`s`s" `` ] - The literal string that is added to the
left and right side of every column, EXCEPT the left side of the first column and the right
side of the last column. Use `Options.LinePrefix` and `Options.LineSuffix` to adjust the
left side of the first column and the right side of the last column.
- **{String}** [ `` Options.InputColumnSeparator = "`t" `` ] - A RegEx pattern that identifies the
boundary between columns.
- **{String}** [ `Options.InputRowSeparator = "\R"` ] - A RegEx pattern that identifies the
boundary between rows.
- **{String}** [ `Options.LinePrefix = ""` ] - The literal string that is added before every line.
- **{String}** [ `Options.LineSuffix = ""` ] - The literal string that is added after every line.
- **{Integer|Integer[]}** [ `Options.MaxWidths = ""` ] - If in use, `Options.MaxWidths` is an array of
integers which define the maximum allowable width per column. If the text in a cell exceeds the
maximum, `MakeTable` breaks the text into multiple lines. If `Options.MaxWidths` is an integer,
that value is applied as the max width of all columns.
- **{String[]}** [ `Options.OutputColumnPrefix = ""` ] - Used to specify strings that prefix
columns. The difference between `Options.OutputColumnPrefix` and `Options.OutputColumnSeparator`
is that `Options.OutputColumnSeparator` is applied to all columns, whereas
`Options.OutputColumnPrefix` is used to prefix every line of a specific column with a specific
string. The value of this option, if used, should be an array of strings. The indices of the
array are associated with the column index that is to be prefixed by the string at that index.
For example, if I have a table that is three columns, and I want to prefix each line of the
third column with "; ", then I would set `Options.ColumnPrefix := ["", "", "; "]`. I added
this option with the intent of using it to comment out portions of text when using `MakeTable`
to generate pretty-formatted code.
- **{Boolean}** [ `Options.OutputColumnPrefixSkipFirstRow = false` ] - If true, the first
line is not affected by `Options.OutputColumnPrefix`.
- **{String}** [ `Options.OutputColumnSeparator = ""` ] - The literal string that is used to
separate cells.
- **{Boolean}** [ `Options.OutputLineBetweenRows = false` ] - If true, there will be an extra line
separating the rows. The line will look just like the header separator seen in the above
examples.
- **{String}** [ `` Options.OutputRowSeparator = "`n" `` ] - The literal string that is used to
separate rows.
- **{String}** [ `` Options.TrimCharacters = "`s" `` ] - The value passed to the third parameter
of `StrSplit` when breaking the input text into rows and cells. `Options.TrimCharactersRow`
and `Options.TrimCharactersCell` supercede `Options.TrimCharacters`. For example, if
you set `` Options.TrimCharacters := "`s" `` and `Options.TrimCharactersRow := "$"`, the characters
trimmed from the left and right side of each line is "$" and the characters trimmed from the
left and right side of each cell is "`s" (space).
[https://www.autohotkey.com/docs/v2/lib/StrSplit.htm](https://www.autohotkey.com/docs/v2/lib/StrSplit.htm).
- **{String}** [ `Options.TrimCharactersRow = ""` ] - The value passed to the third parameter
of `StrSplit` when breaking the input text into lines. `Options.TrimCharactersRow`
and `Options.TrimCharactersCell` supercede `Options.TrimCharacters`. For example, if
you set `` Options.TrimCharacters := "`s" `` and `Options.TrimCharactersRow := "$"`, the characters
trimmed from the left and right side of each line is "$" and the characters trimmed from the
left and right side of each cell is "`s" (space).
[https://www.autohotkey.com/docs/v2/lib/StrSplit.htm](https://www.autohotkey.com/docs/v2/lib/StrSplit.htm).
- **{String}** [ `Options.TrimCharactersCell = ""` ] - The value passed to the third parameter
of `StrSplit` when breaking the text lines into individual cells. `Options.TrimCharactersRow`
and `Options.TrimCharactersCell` supercede `Options.TrimCharacters`. For example, if
you set `` Options.TrimCharacters := "`s" `` and `Options.TrimCharactersRow := "$"`, the characters
trimmed from the left and right side of each line is "$" and the characters trimmed from the
left and right side of each cell is "\`s" (space).
[https://www.autohotkey.com/docs/v2/lib/StrSplit.htm](https://www.autohotkey.com/docs/v2/lib/StrSplit.htm).
## The MakeTable object
The `MakeTable` object is an array of arrays of arrays of strings.
Each item of the `MakeTable` array is a `MakeTable_Row` representing a row in the table.
Each item of the `MakeTable_Row` arrays is a `MakeTable_Cell` object representing
a cell in the table. `MakeTable_Cell` objects are arrays of strings, where each item
represent a line of text for that cell. If you call the object, i.e.
`MakeTable_Cell.Prototype.Call`, it will return the full text within the cell.
If `Options.MaxWidths` is not in use, then the length of the `MakeTable_Cell` array is always 1 (no cells
are broken into multiple lines). If `Options.MaxWidths` is in use, then the length of the array
is the number of lines that the text was broken into for that cell. The property
"RowLines" is an array of integers representing the number of lines each
row occupies, which is the greatest number of lines into which the text within any cell in that
row was split.
Accessing a string value in the array looks like this:
```ahk
; Assume `inputStr` and `options` are appropriately defined.
tbl := MakeTable(inputStr, options)
r := 1 ; row index
c := 1 ; column index
k := 1 ; line index
text := tbl[r][c][k]
```
Accessing the text in a cell looks like this:
```ahk
; Assume `inputStr` and `options` are appropriately defined.
tbl := MakeTable(inputStr, options)
r := 1 ; row index
c := 1 ; column index
cell := tbl[r][c]
text := cell() ; call the cell object to get the entire cell's text content
```
You can produce a markdown table that is both pretty-aligned and valid markdown. To do that,
use the following options (in addition to any other options you might want). We can't use
`Options.MaxWidths` when producing markdown output because the line breaks will disrupt the markdown
syntax. `Options.MaxWidths` is disabled by default. Use `MakeTable.Prototype.GetMarkdown` to
include line breaks in your markdown table.
```ahk
options := {
AddHeaderSeparator: true
, InputColumnSeparator: ',' ; set to whatever character / pattern identifies the boundary between each column
, LinePrefix: "| "
, LineSuffix: " |"
, OutputColumnSeparator: "|"
}
tbl := MakeTable(inputString, options)
```
The above options will yield output like this:
```markdown
| calldate | src | dst | dcontext | channel |
| ---------------------|--------------|---------|-------------------------|----------------------------------------------- |
| 07/14/2025 02:43:44 | 5555557485 | 17 | play-system-recording | PJSIP/Cox_Trunk-0000d-212-1080-@from-internal |
| 07/14/2025 05:58:22 | 5555557984 | s | ivr-6 | PJSIP/Cox_Trunk-0000d-213-1080-@from-internal |
| 07/14/2025 06:36:41 | 5555559989 | s | ivr-6 | PJSIP/Cox_Trunk-0000d-214-1080-@from-internal |
| 07/14/2025 06:47:11 | 5555552202 | 91017 | ext-queues | PJSIP/Cox_Trunk-0000d-215-1080-@from-internal |
```
# MakeTable.Prototype.GetMarkdown
Use `MakeTable.Prototype.GetMarkdown` to produce a markdown table.
## Parameters
- **{String}** [ `` LineSeparator = "`n" `` ] - The string that separates each line in the output
string.
- **{String}** [ `InnerLineSeparator = ""` ] - The value passed to the parameter
`Separator` which is used to separate each line of text within a cell when `Options.MaxWidths` is
used. For example, if your cells contain very long strings that would look better broken up into
multiple lines, you can set the `Options.MaxWidths` with an integer or array of integers. This will
break up the text into multiple lines for cells that exceed the maximum. Then, when you call
`MakeTable.Prototype.GetMarkdown`, you can set parameter `InnerLineSeparator` with a string to
separate those lines. Use "<br>" to separate the lines with line breaks.
## Returns
**{String}** - The markdown table.
`MakeTable.Prototype.GetMarkdown` has one benefit that is not available directly from the `MakeTable`
core process - with `MakeTable.Prototype.GetMarkdown` we can also include <br> tags in-between
long lines of text. We do that by setting the [InnerLineSeparator](#maketableprototypegetmarkdown)
parameter with "<br>", yielding an output like the below table, which will render correctly and
will include line breaks at the <br> tags.
```markdown
|calldate|src|dst|dcontext|channel|
|-|-|-|-|-|
|07/14/2025
02:43:44|5555557485|17|play-system-reco
rding|PJSIP/Cox_Trunk-
0000d-212-1080-@
from-internal|
|07/14/2025
05:58:22|5555557984|s|ivr-6|PJSIP/Cox_Trunk-
0000d-213-1080-@
from-internal|
|07/14/2025
06:36:41|5555559989|s|ivr-6|PJSIP/Cox_Trunk-
0000d-214-1080-@
from-internal|
|07/14/2025
06:47:11|5555552202|91017|ext-queues|PJSIP/Cox_Trunk-
0000d-215-1080-@
from-internal|
```
# MakeTable.Prototype.GetHtml
Use `MakeTable.Prototype.GetHtml` to produce an html table.
## Parameters
- **{String}** [ `` Options.IndentChar = "`s" `` ] - The character that is used for indentation.
- **{Integer}** [ `` Options.IndentLen = 2 `` ] - The number of `Options.IndentChar` that is used
for one level of indentation.
- **{Integer}** [ `` Options.InitialIndent = 0 `` ] - The initial indentation level of the output
string.
- **{String}** [ `` Options.InnerLineSeparator = "" `` ] - The value passed to the parameters
`MakeTable_Cell.Prototype.Call~Separator` which is used to separate each line of text
within a cell when `MakeTable.Prototype.__New~Options.MaxWidths` is used. For example,
if your cells contain very long strings that would look better broken up into multiple lines,
you can set the "MaxWidths" property of the options object that you pass to
`MakeTable.Prototype.__New`. This will break up the text into multiple lines for cells
that exceed the maximum. Then, when you call `MakeTable.Prototype.GetHtml`, you can
set `Options.InnerLineSeparator` with a substring to separate those lines. A good option
is "<br>". An empty string is also an appropriate option.
- **{String}** [ `` Options.LineSeparator = "`n" `` ] - The literal string that separates each line
in the output string.
- **{String}** [ `` Options.TableAttribute = "" `` ] - Any attributes you want included with the
<table> element, e.g. "class=`"tbl-class`" border=`"1`"". Separate each individual attribute
with a space character.
- **{String}** [ `` Options.TableStyle = "" `` ] - The style attribute value that will be
included with the <table> elements. Only include the value that goes between the quotation
marks of the style attribute, e.g. "color:red;".
- **{String|String[]|String[][]}** [ `` Options.TdAttribute = "" `` ] - If a string, the attribute
that will be included with all <td> elements.
- If an array of strings, each index in the array corresponds to a row in the table (not
including headers) and that string is applied as the attributes for each cell in the row.
For example, index 1 is the first row after the headers.
- If an array of arrays of strings, each index of the outer array corresponds with a row in the
table (not including headers). For example, index 1 is the first row after the headers. Each
index of the inner array corresponds with a cell in that row. For example, index 1 is the
first cell in the row. The items of the inner array are strings that wil be applied as the
attributes for the corresponding cell.
- The arrays must have the correct number of items for the table content. If there are too few
items, an IndexError will occur.
- Separate each individual attribute with a space character.
- For example, these are each valid, assuming the table has 3 data rows and 3 columns:
```ahk
options := { TdAttribute: "class=`"td-class`"" }
options := { TdAttribute: [ "class=`"td-class-1`"", "class=`"td-class-2`"", "class=`"td-class-3`"" ] }
options := { TdAttribute: [
[ "class=`"td-class-1-1`"", "class=`"td-class-1-2`"", "class=`"td-class-1-3`"" ]
, [ "class=`"td-class-2-1`"", "class=`"td-class-2-2`"", "class=`"td-class-2-3`"" ]
, [ "class=`"td-class-3-1`"", "class=`"td-class-3-2`"", "class=`"td-class-3-3`"" ]
]}
```
- **{String}** [ `` Options.TdStyle = "" `` ] - If a string, the style attribute value that will be
included with all <td> elements. Only include the value that goes between the quotation marks
of the style attribute, e.g. "color:red;".
- If an array of strings, each index in the array corresponds to a row in the table (not
including headers) and that string is applied as the attributes for each cell in the row.
For example, index 1 is the first row after the headers.
- If an array of arrays of strings, each index of the outer array corresponds with a row in the
table (not including headers). For example, index 1 is the first row after the headers. Each
index of the inner array corresponds with a cell in that row. For example, index 1 is the
first cell in the row. The items of the inner array are strings that wil be used as the style
attribute value for the corresponding cell.
- The arrays must have the correct number of items for the table content. If there are too few
items, an IndexError will occur.
- For example, these are each valid, assuming the table has 3 data rows and 3 columns:
```ahk
options := { TdStyle: "color:red;" }
options := { TdStyle: [ "color:red;", "color:green;", "color:blue;" ] }
options := { TdStyle: [
[ "color:red;", "color:green;", "color:blue;" ]
, [ "color:blue;", "color:red;", "color:green;" ]
, [ "color:green;", "color:blue;", "color:red;" ]
]}
```
- **{String|String[]}** [ `` Options.ThAttribute = "" `` ] - If a string, the attribute
that will be included with all <th> elements.
- If an array of strings, each index in the array corresponds to an individual header.
- The arrays must have the correct number of items for the table content. If there are too few
items, an IndexError will occur.
- Separate each individual attribute with a space character.
- For example, these are each valid, assuming the table has a header row with 3 headers.
```ahk
options := { ThAttribute: "class=`"th-class`"" }
options := { ThAttribute: [ "class=`"th-class-1`"", "class=`"th-class-2`"", "class=`"th-class-3`"" ] }
```
- **{String}** [ `` Options.ThStyle = "" `` ] - If a string, the style attribute value that will be
included with all <th> elements. Only include the value that goes between the quotation marks
of the style attribute, e.g. "color:red;".
- If an array of strings, each index in the array corresponds to a row in the table (not including
headers).
- The arrays must have the correct number of items for the table content. If there are too few
items, an IndexError will occur.
- For example, these are each valid, assuming the table has a header row with 3 headers.
```ahk
options := { ThStyle: "color:red;" }
options := { ThStyle: [ "color:red;", "color:green;", "color:blue;" ] }
```
- **{String}** [ `` Options.TrAttribute = "" `` ] - If a string, the attribute
that will be included with all <tr> elements.
- If an array of strings, each index in the array corresponds to a row in the table (not including
headers).
- The arrays must have the correct number of items for the table content. If there are too few
items, an IndexError will occur.
- Separate each individual attribute with a space character.
- For example, these are each valid, assuming the table has 3 rows.
```ahk
options := { TrAttribute: "class=`"tr-class`"" }
options := { TrAttribute: [ "class=`"tr-class-1`"", "class=`"tr-class-2`"", "class=`"tr-class-3`"" ] }
```
- **{String}** [ `` Options.TrStyle = "" `` ] - If a string, the style attribute value that will be
included with all <tr> elements. Only include the value that goes between the quotation marks
of the style attribute, e.g. "color:red;".
- If an array of strings, each index in the array corresponds to a row in the table (not including
headers).
- The arrays must have the correct number of items for the table content. If there are too few
items, an IndexError will occur.
- For example, these are each valid, assuming the table has 3 rows.
```ahk
options := { TrStyle: "color:red;" }
options := { TrStyle: [ "color:red;", "color:green;", "color:blue;" ] }
```
## Example without attributes
```html
calldate
src
dst
dcontext
channel
07/14/2025 02:43:44
5555557485
17
play-system-recording
PJSIP/Cox_Trunk-0000d-212-1080-@from-internal
07/14/2025 05:58:22
5555557984
s
ivr-6
PJSIP/Cox_Trunk-0000d-213-1080-@from-internal
07/14/2025 06:36:41
5555559989
s
ivr-6
PJSIP/Cox_Trunk-0000d-214-1080-@from-internal
07/14/2025 06:47:11
5555552202
91017
ext-queues
PJSIP/Cox_Trunk-0000d-215-1080-@from-internal
```
## Example with attributes
```html
calldate
src
dst
dcontext
channel
07/14/2025 02:43:44
5555557485
17
play-system-recording
PJSIP/Cox_Trunk-0000d-212-1080-@from-internal
07/14/2025 05:58:22
5555557984
s
ivr-6
PJSIP/Cox_Trunk-0000d-213-1080-@from-internal
07/14/2025 06:36:41
5555559989
s
ivr-6
PJSIP/Cox_Trunk-0000d-214-1080-@from-internal
07/14/2025 06:47:11
5555552202
91017
ext-queues
PJSIP/Cox_Trunk-0000d-215-1080-@from-internal
```
# Changelog
- **2025-11-14**
- Added property `MakeTableObj.ColumnWidths`, which is an array of integers representing the width,
in character count, of each column.