#!/usr/bin/env python

"""
Indent-aware replacement for TextMate's Reflow Paragraph command.

Could be made smarter-still, particularly with respect to indents
on the first line, but this'll have to do for now!
"""

import re, sys
from os import environ
from sys import stdin, stdout, exit

max_line_width = 78 # Can we get this from TM somehow?
tab_length = int(environ["TM_TAB_SIZE"])
current_line = int(environ["TM_LINE_NUMBER"]) - 1
all_lines = stdin.readlines()
tm_scope = environ["TM_SCOPE"]

initial_whitespace_re = re.compile(r"^\s*")
if tm_scope.startswith("text.tex"):
    delimit_para_re = re.compile(r"^\s*$|^\s*\\begin|^\s*\\end")
else:
    delimit_para_re = re.compile(r"^\s*$")

def is_different_paragraph(current_indent, other_indent):
    return abs(other_indent - current_indent) >= tab_length

def delimits_para(line):
    return delimit_para_re.match(line) is not None
    
def wslen(ws):
    "Given a whitespace string, return displayed length"
    tabs = ws.count("\t")
    return len(ws) - tabs + (tabs * tab_length)

def initial_whitespace(line):
    if line[-1] == '\n': 
        endpos = len(line) - 1
    else:
        endpos = len(line)
    return wslen(initial_whitespace_re.match(line, 0, endpos).group(0))

def search_lines(from_line, inc_line):
    current_indent = initial_whitespace(all_lines[from_line])
    search_line = from_line + inc_line
    while search_line >= 0 and search_line < len(all_lines):
        if delimits_para(all_lines[search_line]): break
        first_indent = initial_whitespace(all_lines[search_line])
        if is_different_paragraph(current_indent, first_indent): break
        search_line += inc_line
    return search_line
    
def print_indent(amnt):
    # XXX Respect soft tabs setting, rather than assume it is ON
    stdout.write(" " * amnt)

# If the current line is purely whitespace, we are not in a paragraph:
if delimits_para(all_lines[current_line]):
    stdout.writelines(all_lines)
    exit(0)

# Identify boundaries of paragraph:
first_line = search_lines(current_line, -1) + 1     # First line in paragraph
last_line = search_lines(current_line, +1)          # First line AFTER paragraph

# Print text before paragraph:
stdout.writelines(all_lines[0:first_line])

# Collect all words in parapgraph and emit reflowed:
indent_width = initial_whitespace(all_lines[first_line])
all_words = "".join(all_lines[first_line:last_line]).split()
print_indent(indent_width)
width = indent_width
for word in all_words:
    word_width = len(word) + 1
    if width + word_width > max_line_width:
        stdout.write("\n")
        print_indent(indent_width)
        width = indent_width
    elif width != indent_width:
        stdout.write(" ")
        width += 1
    stdout.write(word)
    width += len(word)
stdout.write("\n")

# Print text after paragraph:
stdout.writelines(all_lines[last_line:])
