-
Notifications
You must be signed in to change notification settings - Fork 5
FormatTable
Michael Butscher edited this page Jan 23, 2021
·
1 revision
######################################################################## # # FormatTable.py # ------------ # v0.1 by xkjq@ymail.com # ------------ # Script to allow easy formating of tables within wikidpad # # The script has 2 basic functions depending on the context it is used. # Both require the text to be formated to be selected. # # Default shortcut is Ctrl+Alt+T (can be changed below) # # 1. Format a preexisting table. # If a table is selected the script will attempt to align the # columns as best it can. It should work with either \t or | table # formats. This option will be used if the selected text starts with # "<<|" and ends with ">>". If not the section function will be used. # (See - 2. Create table - below) # NOTE: This may not work well with long columns. # # e.g. # The following table: # # <<| # this | is | a | table # which | is | not | well # aligned | or | formatted | nicely # >> # # will be replaced by: # # <<| # this | is | a | table # which | is | not | well # aligned | or | formatted | nicely # >> # # Linebreaks using "\" are also supported # # 2. Create Table # If not table is selected the script will attempt to create # a table from the selected text, assuming that the table is currently # in the format of # # colum 1 row 1 # colum 1 row 2 # colum 1 row 3 # colum 1 row ... # colum 2 row 1 # colum 2 row 2 # colum 2 row 3 # colum 2 row ... # colum 3 row 1 # colum 3 row 2 # colum 3 row 3 # colum 3 row ... # colum ... row ... # etc.... # # Which can be rewrapped into # <<| # colum 1 row 1 | colum 2 row 1 | colum 3 row 1 # colum 1 row 2 | colum 2 row 2 | colum 3 row 2 # colum 1 row 3 | colum 2 row 3 | colum 3 row 3 # colum 1 row ... | colum 2 row ... | colum 3 row ... # >> # By selected the text and entering the desired number of columns. # It is important you have the correct number of rows selected. # ######################################################################## import urllib, wx, wx.stc, re import collections WIKIDPAD_PLUGIN = (("MenuFunctions",1),) # NOTE: Some of the code below is specific for my custom parser # it should however be fully backwards compatible with the # wikidpad default 2.0 parser. REMOVE_BLANK_LINES = True USE_PLUS_FORMATTING = True def describeMenuItems(wiki): return ((buildTable, "Format Table\tCtrl+Alt+T", "Format a table."),) class TableDlg(wx.Dialog): def __init__(self, *args, **kwds): kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) def TableNo(self, no): pos = [] for i in range(2, no/2+1): if not no % i: pos.append(str(i)) dlg = wx.TextEntryDialog(self, 'How many columns? (N = {0}, pos = {1})'.format(no, ",".join(pos)), ) if dlg.ShowModal() == wx.ID_OK: return int(dlg.GetValue()) dlg.Destroy() def splitLineIntoColumns(sep, line): """ The column has to be split by a regex if "|" formating is being used as otherwise we can get into trouble with links (which can also contain "|". """ if sep == u"|": # We cheat a bit here (this is by no means foolproof) # but it seems to work in most cases I've encountered so far # (providing [ ] are matched) return re.split("\|(?!(?:[^[])*\])", line) else: return line.split(sep) def buildTable(wiki, evt): editor = wiki.getActiveEditor() beginSel=editor.GetSelectionStart() endSel=editor.GetSelectionEnd() oldPos=editor.GetCurrentPos() editor.GotoPos(beginSel) editor.CmdKeyExecute(wx.stc.STC_CMD_HOMEEXTEND) beginSel = editor.GetSelectionStart() editor.GotoPos(endSel) editor.CmdKeyExecute(wx.stc.STC_CMD_LINEENDEXTEND) endSel = editor.GetSelectionEnd() editor.SetSelection(beginSel, endSel) text = wiki.getActiveEditor().GetSelectedText() if not text.strip()[:3] == "<<|" or not text.strip()[-2:] == ">>": a = text.split("\n") no = TableDlg(wiki).TableNo(len(a)) if not no: return b = [] if not len(a) % no: b.append("<<|") n = len(a)/no for i in range(n): line = a[i] for j in range(no)[:-1]: j = j+1 line += " | " + a[j*n+i] b.append(line) b.append(">>") c = "\n".join(b) else: c = text text = c lines = text.split("\n") if REMOVE_BLANK_LINES: lines = [i for i in lines if len(i.strip()) > 0] string_length = collections.defaultdict(int) new_lines = [] appedix_start = u"<<|" if lines[0][:4] == u"<<|t": appedix_start = u"<<|t" sep = u"\t" n = 2 else: sep = u"|" n = 0 start_line = 1 appendix = lines[0][len(appedix_start):].split(";") # Check if caption is present if u"C" in appendix: start_line = 2 cells = [] # First we check the maximum number of columns present in the table total_count = 0 for line in lines[start_line:-1]: count = line.count(sep) # correct for links: [link|name] if sep == u"|": count -= len(re.findall("\[.*\|.*\]", line)) if total_count > 0: count = count + total_count if line.endswith("\\"): total_count = count else: cells.append(count) total_count = 0 cell_no = max(cells) n = start_line column_len = collections.defaultdict(int) column_no = 0 # Find max column lengths data = collections.defaultdict(list) while n < len(lines): columns = splitLineIntoColumns(sep, lines[n]) print columns new_row = True for column in columns: skip = False # endswith? if len(column) > 0 and column[-1] == u"\\": column = column[:-1] column = column.strip() if new_row and column_no > 0: column = column[1:].strip() for appendix in column.split(";"): # TODO: size for with appendixes? if re.match("c\d", appendix): skip = True if not skip: data[column_no].append(column) #if len(column) > column_len[column_no] and not skip: # column_len[column_no] = len(column) #column_no += 1 new_row = False column_no += 1 if columns[-1].endswith("\\"): column_no -= 1 else: column_no = 0 n += 1 for i in data: column_len[i] = max([len(column) for column in data[i]]) def Blank(n): if n > 0: return n * u" " else: return u"" n = 1 column_no = 0 while n < len(lines) - 1: columns = splitLineIntoColumns(sep, lines[n]) newline = [] new_row = True for column in columns: force_add_whitespace = False column = column.strip() col_len = len(column) if new_row and column_no > 0: extra = u" " # Test for + if USE_PLUS_FORMATTING and column[0] == "+": extra = u"+" column = column[1:].strip() col_len = len(column) elif not column.endswith("\\") and column_no != len(columns): force_add_whitespace = True for i in range(column_no): column = "".join([Blank(column_len[i]), column]) column = "".join([extra, Blank(3 * column_no - 1), column]) if (column_no < cell_no or force_add_whitespace) and not column.endswith("\\") and not column_no >= cell_no: extra = Blank(column_len[column_no]-col_len) else: extra = u"" newline.append(column + extra) column_no += 1 new_row = False if columns[-1].endswith("\\"): column_no -= 1 else: column_no = 0 n += 1 new_lines.append(" {0} ".format(sep).join(newline)) text = lines[0] + "\n" + "\n".join(new_lines) + "\n>>" new_text_len = len(text) editor.ReplaceSelection(text) editor.SetCurrentPos(beginSel) editor.SetAnchor(beginSel)