فهرست منبع

Merge pull request #3812 from Feoramund/add-table-decorations

Add `write_decorated_table` to `text/table`
Jeroen van Rijn 1 سال پیش
والد
کامیت
3726f0b73c
2فایلهای تغییر یافته به همراه130 افزوده شده و 0 حذف شده
  1. 51 0
      core/text/table/doc.odin
  2. 79 0
      core/text/table/table.odin

+ 51 - 0
core/text/table/doc.odin

@@ -265,5 +265,56 @@ This will print out:
 	| Excessive Diacritics        | H̷e̶l̵l̸o̴p̵e̷ ̸w̶o̸r̵l̶d̵!̴                                                                               |
 	+-----------------------------+----------------------------------------------------------------------------------------------+
 
+**Decorated Tables:**
+
+If you'd prefer to change the borders used by the plain-text table printing,
+there is the `write_decorated_table` procedure that allows you to change the
+corners and dividers.
+
+Here is a complete example:
+
+	package main
+
+	import "core:fmt"
+	import "core:io"
+	import "core:os"
+	import "core:text/table"
+
+	box_drawing :: proc(w: io.Writer) {
+		t: table.Table
+		table.init(&t)
+		table.caption(&t, "Box Drawing Example")
+		table.padding(&t, 2, 2)
+		table.header_of_aligned_values(&t, {{.Left, "Operating System"}, {.Center, "Year Introduced"}})
+
+		table.row(&t, "UNIX",                "1973")
+		table.row(&t, "MS-DOS",              "1981")
+		table.row(&t, "Commodore 64 KERNAL", "1982")
+		table.row(&t, "Mac OS",              "1984")
+		table.row(&t, "Amiga",               "1985")
+		table.row(&t, "Windows 1.0",         "1985")
+		table.row(&t, "Linux",               "1991")
+		table.row(&t, "Windows 3.1",         "1992")
+
+		decorations := table.Decorations {
+			"┌", "┬", "┐",
+			"├", "┼", "┤",
+			"└", "┴", "┘",
+			"│", "─",
+		}
+
+		table.write_decorated_table(w, &t, decorations)
+		fmt.println()
+	}
+
+	main :: proc() {
+		stdout := os.stream_from_handle(os.stdout)
+
+		box_drawing(stdout)
+	}
+
+While the decorations support multi-codepoint Unicode graphemes, do note that
+each border character should not be larger than one monospace cell.
+
 */
 package text_table

+ 79 - 0
core/text/table/table.odin

@@ -51,6 +51,19 @@ Table :: struct {
 	tblw: int,          // Width of entire table (including padding, excluding borders)
 }
 
+Decorations :: struct {
+	// These are strings, because of multi-codepoint Unicode graphemes.
+
+	// Connecting decorations:
+	nw, n, ne,
+	 w, x,  e,
+	sw, s, se: string,
+
+	// Straight lines:
+	vert: string,
+	horz: string,
+}
+
 ascii_width_proc :: proc(str: string) -> int {
 	return len(str)
 }
@@ -397,6 +410,72 @@ write_plain_table :: proc(w: io.Writer, tbl: ^Table, width_proc: Width_Proc = un
 	write_table_separator(w, tbl)
 }
 
+write_decorated_table :: proc(w: io.Writer, tbl: ^Table, decorations: Decorations, width_proc: Width_Proc = unicode_width_proc) {
+	draw_dividing_row :: proc(w: io.Writer, tbl: ^Table, left, horz, divider, right: string) {
+		io.write_string(w, left)
+		for col in 0..<tbl.nr_cols {
+			for _ in 0..<tbl.colw[col] + tbl.lpad + tbl.rpad {
+				io.write_string(w, horz)
+			}
+			if col < tbl.nr_cols-1 {
+				io.write_string(w, divider)
+			}
+		}
+		io.write_string(w, right)
+		io.write_byte(w, '\n')
+	}
+
+	build(tbl, width_proc)
+
+	// This determines whether or not to divide the top border.
+	top_divider := decorations.n if len(tbl.caption) == 0 else decorations.horz
+
+	// Draw the north border.
+	draw_dividing_row(w, tbl, decorations.nw, decorations.horz, top_divider, decorations.ne)
+
+	if len(tbl.caption) != 0 {
+		// Draw the caption.
+		io.write_string(w, decorations.vert)
+		write_text_align(w, tbl.caption, .Center,
+			tbl.lpad, tbl.rpad, tbl.tblw + tbl.nr_cols - 1 - width_proc(tbl.caption) - tbl.lpad - tbl.rpad)
+		io.write_string(w, decorations.vert)
+		io.write_byte(w, '\n')
+
+		// Draw the divider between the caption and the table rows.
+		draw_dividing_row(w, tbl, decorations.w, decorations.horz, decorations.n, decorations.e)
+	}
+
+	// Draw the header.
+	start := 0
+	if tbl.has_header_row {
+		io.write_string(w, decorations.vert)
+		row := header_row(tbl)
+		for col in 0..<tbl.nr_cols {
+			write_table_cell(w, tbl, row, col)
+			io.write_string(w, decorations.vert)
+		}
+		io.write_byte(w, '\n')
+		start += row + 1
+
+		draw_dividing_row(w, tbl, decorations.w, decorations.horz, decorations.x, decorations.e)
+	}
+
+	// Draw the cells.
+	for row in start..<tbl.nr_rows {
+		for col in 0..<tbl.nr_cols {
+			if col == 0 {
+				io.write_string(w, decorations.vert)
+			}
+			write_table_cell(w, tbl, row, col)
+			io.write_string(w, decorations.vert)
+		}
+		io.write_byte(w, '\n')
+	}
+
+	// Draw the south border.
+	draw_dividing_row(w, tbl, decorations.sw, decorations.horz, decorations.s, decorations.se)
+}
+
 // Renders table according to GitHub Flavored Markdown (GFM) specification
 write_markdown_table :: proc(w: io.Writer, tbl: ^Table, width_proc: Width_Proc = unicode_width_proc) {
 	// NOTE(oskar): Captions or colspans are not supported by GFM as far as I can tell.