From 6acffd61793ef5f3e9171748b506bf971bdeb2ac Mon Sep 17 00:00:00 2001 From: bitwiser Date: Sat, 29 Oct 2016 00:17:27 +0200 Subject: [PATCH] alpha --- .gitignore | 1 + Default (Linux).sublime-keymap | 9 +++ Default (OSX).sublime-keymap | 9 +++ Default (Windows).sublime-keymap | 9 +++ Main.sublime-menu | 88 +++++++++++++++++++++++++ MarkdownTableFormatter.sublime-settings | 4 ++ markdown_table_formatter.py | 32 +++++++++ simple_markdown/__init__.py | 0 simple_markdown/table.py | 66 +++++++++++++++++++ tests/test.py | 67 +++++++++++++++++++ 10 files changed, 285 insertions(+) create mode 100644 .gitignore create mode 100644 Default (Linux).sublime-keymap create mode 100644 Default (OSX).sublime-keymap create mode 100644 Default (Windows).sublime-keymap create mode 100644 Main.sublime-menu create mode 100644 MarkdownTableFormatter.sublime-settings create mode 100644 markdown_table_formatter.py create mode 100644 simple_markdown/__init__.py create mode 100644 simple_markdown/table.py create mode 100755 tests/test.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap new file mode 100644 index 0000000..113e0a9 --- /dev/null +++ b/Default (Linux).sublime-keymap @@ -0,0 +1,9 @@ +[ + { + "keys": ["ctrl+alt+shift+t"], + "command": "markdown_table_formatter_format", + "context": [ + {"key": "selector", "operator": "equal", "operand": "text.html.markdown"} + ] + } +] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap new file mode 100644 index 0000000..113e0a9 --- /dev/null +++ b/Default (OSX).sublime-keymap @@ -0,0 +1,9 @@ +[ + { + "keys": ["ctrl+alt+shift+t"], + "command": "markdown_table_formatter_format", + "context": [ + {"key": "selector", "operator": "equal", "operand": "text.html.markdown"} + ] + } +] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap new file mode 100644 index 0000000..113e0a9 --- /dev/null +++ b/Default (Windows).sublime-keymap @@ -0,0 +1,9 @@ +[ + { + "keys": ["ctrl+alt+shift+t"], + "command": "markdown_table_formatter_format", + "context": [ + {"key": "selector", "operator": "equal", "operand": "text.html.markdown"} + ] + } +] diff --git a/Main.sublime-menu b/Main.sublime-menu new file mode 100644 index 0000000..c1c0385 --- /dev/null +++ b/Main.sublime-menu @@ -0,0 +1,88 @@ +[ + { + "caption": "Preferences", + "mnemonic": "n", + "id": "preferences", + "children": + [ + { + "caption": "Package Settings", + "mnemonic": "P", + "id": "package-settings", + "children": + [ + { + "caption": "Markdown Table Formatter", + "children": + [ + { + "command": "open_file", "args": + { + "file": "${packages}/MarkdownTableFormatter/MarkdownTableFormatter.sublime-settings" + }, + "caption": "Settings – Default" + }, + { + "command": "open_file", "args": + { + "file": "${packages}/User/MarkdownTableFormatter.sublime-settings" + }, + "caption": "Settings – User" + }, + { "caption": "-" }, + { + "command": "open_file", + "args": { + "file": "${packages}/MarkdownTableFormatter/Default (OSX).sublime-keymap", + "platform": "OSX" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/MarkdownTableFormatter/Default (Linux).sublime-keymap", + "platform": "Linux" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/MarkdownTableFormatter/Default (Windows).sublime-keymap", + "platform": "Windows" + }, + "caption": "Key Bindings – Default" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/User/Default (OSX).sublime-keymap", + "platform": "OSX" + }, + "caption": "Key Bindings – User" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/User/Default (Linux).sublime-keymap", + "platform": "Linux" + }, + "caption": "Key Bindings – User" + }, + { + "command": "open_file", + "args": { + "file": "${packages}/User/Default (Windows).sublime-keymap", + "platform": "Windows" + }, + "caption": "Key Bindings – User" + }, + { "caption": "-" } + ] + } + ] + } + ] + } +] \ No newline at end of file diff --git a/MarkdownTableFormatter.sublime-settings b/MarkdownTableFormatter.sublime-settings new file mode 100644 index 0000000..0b197a9 --- /dev/null +++ b/MarkdownTableFormatter.sublime-settings @@ -0,0 +1,4 @@ +{ + // make plugin verbose + "verbose" : true +} diff --git a/markdown_table_formatter.py b/markdown_table_formatter.py new file mode 100644 index 0000000..f174f1d --- /dev/null +++ b/markdown_table_formatter.py @@ -0,0 +1,32 @@ +import sublime +import sublime_plugin + +import logging + +from . import simple_markdown as markdown +from .simple_markdown import table + +log = logging.getLogger(__name__) + +class MarkdownTableFormatterFormatCommand(sublime_plugin.TextCommand): + def run(self, edit): + logging.basicConfig(level=logging.DEBUG) + for region in self.view.sel(): + text = self.view.substr(region) + # get all tables positions as (start,end) list + positions = markdown.table.find_all(text) + offset = 0 + for start, end in positions: + raw_table = text[start:end] + log.debug("table found:\n" + raw_table) + table = markdown.table.format(raw_table) + log.debug("formatted output:\n" + table) + + # replace the raw table with the formetted one + table_region = sublime.Region(region.begin() + start + offset, + region.begin() + end + offset) + self.view.replace(edit, table_region, table) + + # as table length will likely change, an offset is required to + # keep the modified region consistent + offset = offset + len(table) - (end - start) diff --git a/simple_markdown/__init__.py b/simple_markdown/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/simple_markdown/table.py b/simple_markdown/table.py new file mode 100644 index 0000000..1960d62 --- /dev/null +++ b/simple_markdown/table.py @@ -0,0 +1,66 @@ +import re + +def find_all(text): + tables = [] + offset = 0 + while True: + group = re.search(".*\|.*\n[\s\t]*\|?(?::?[-]+:?\|)+(\n.*\|.*)+", + text[offset:], re.MULTILINE) + if group is None: + return tables + tables.append((group.start() + offset, group.end() + offset)) + offset = offset + group.end() + return tables + +def format(raw_table): + rows = raw_table.splitlines() + # normalize markdown table, add missing leading/trailing '|' + for idx, row in enumerate(rows): + if re.match("^[\s\t]*\|", row) is None: + rows[idx] = "|" + rows[idx] + if re.match(".*\|[\s\t]*\n?$", row) is None: + rows[idx] = rows[idx] + "|" + + matrix = [[col.strip() for col in row.split("|")] for row in rows] + + # remove first and last empties column + matrix[:] = [row[1:] for row in matrix] + matrix[:] = [row[:-1] for row in matrix] + + # ensure there's same column number for each row or add missings + cols = max([len(row) for row in matrix]) + matrix[:] = \ + [row if len(row) == cols else row+[""]*(cols-len(row)) for row in matrix] + + # merge the multiple "-" of the 2nd line + matrix[1] = [re.sub("[- ]+","-", col) for col in matrix[1]] + + # determine each column size + widths = [[len(col) for col in row] for row in matrix] + max_widths = [max(item) for item in zip(*widths)] + + # construct a clean markdown table without separation row + table = [] + for row_idx, row in enumerate(matrix): + line = ["|"] + # keep separation row for later... + if row_idx == 1: + continue + for col_idx, col in enumerate(row): + line.append(" " + col.ljust(max_widths[col_idx]) + " |") + table.append("".join(line)) + + # construct separation row + sep_row = [] + for col_idx, col in enumerate(matrix[1]): + line = list("-" * (max_widths[col_idx] + 2)) + if col.startswith(":"): + line[0] = ":" + if col.endswith(":"): + line[-1] = ":" + else: + line[0] = ":" + sep_row.append("".join(line)) + table.insert(1, "|" + "|".join(sep_row) + "|") + return "\n".join(table) + diff --git a/tests/test.py b/tests/test.py new file mode 100755 index 0000000..c93a8dc --- /dev/null +++ b/tests/test.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*_ + +import os +import sys + +sys.path.append(os.path.realpath('..')) +import simple_markdown.table + +#import unittest + +raw_table = """\ +| Tables | Are | Cool | +|-------------|:-------------|:-----:| + | col 1 is | left-aligned | $1600 | +col 2 is || $12 + | zebra stripes | are neat | $1 | +|| |$hello +| $2 |""" + +expected_table = """\ +| Tables | Are | Cool | +|:--------------|:-------------|:------:| +| col 1 is | left-aligned | $1600 | +| col 2 is | | $12 | +| zebra stripes | are neat | $1 | +| | | $hello | +| $2 | | |""" + +print(raw_table) +table = simple_markdown.table.format(raw_table) +print(table) + +if table == expected_table: + print("OK") + +junk_tables = """ +| Tables | Are | Cool #1 | +|-------------|:-------------:|:-----| + | col 3 is | right-aligned | $1600 | +col 2 is || $12 + | zebra stripes|are neat| $1 | +|| |$hello +| $2 | + +hellobar +fooworld +and junk + +| Tables | Are | Cool #2 | +|-------------|:-------------:|:-----| + | col 3 is | right-aligned | $1600 | +col 2 is || $12 + | zebra stripes | are neat | $1 | +|| |$hello +| $2 | + +junk junk junk +and some | to test +if it's still working |||||| +is it? +""" + +offsets = simple_markdown.table.find_all(junk_tables) +for offset in offsets: + table = simple_markdown.table.format(junk_tables[offset[0]:offset[1]]) + print(table + "\n")