2019-03-31 02:16:18 +00:00
|
|
|
from gettext import gettext as _
|
|
|
|
|
2019-06-22 03:25:43 +00:00
|
|
|
from uberwriter.helpers import user_action
|
|
|
|
|
2019-03-31 02:16:18 +00:00
|
|
|
|
|
|
|
class FormatInserter:
|
|
|
|
"""Manages insertion of formatting.
|
|
|
|
|
|
|
|
Methods can be called directly, as well as be used as signal callbacks."""
|
|
|
|
|
|
|
|
def insert_italic(self, text_view, _data=None):
|
|
|
|
"""Insert italic or mark a selection as bold"""
|
|
|
|
|
|
|
|
self.__wrap(text_view, "_", _("italic text"))
|
|
|
|
|
|
|
|
def insert_bold(self, text_view, _data=None):
|
|
|
|
"""Insert bold or mark a selection as bold"""
|
|
|
|
|
|
|
|
self.__wrap(text_view, "**", _("bold text"))
|
|
|
|
|
|
|
|
def insert_strikethrough(self, text_view, _data=None):
|
|
|
|
"""Insert strikethrough or mark a selection as strikethrough"""
|
|
|
|
|
|
|
|
self.__wrap(text_view, "~~", _("strikethrough text"))
|
|
|
|
|
|
|
|
def insert_horizontal_rule(self, text_view, _data=None):
|
|
|
|
"""Insert horizontal rule"""
|
|
|
|
|
|
|
|
text_buffer = text_view.get_buffer()
|
2019-06-22 03:25:43 +00:00
|
|
|
with user_action(text_buffer):
|
|
|
|
text_buffer.insert_at_cursor("\n\n---\n")
|
2019-03-31 02:16:18 +00:00
|
|
|
text_view.scroll_mark_onscreen(text_buffer.get_insert())
|
|
|
|
|
|
|
|
def insert_list_item(self, text_view, _data=None):
|
|
|
|
"""Insert list item or mark a selection as list item"""
|
|
|
|
|
|
|
|
text_buffer = text_view.get_buffer()
|
|
|
|
if text_buffer.get_has_selection():
|
|
|
|
(start, end) = text_buffer.get_selection_bounds()
|
|
|
|
if start.starts_line():
|
2019-06-22 03:25:43 +00:00
|
|
|
with user_action(text_buffer):
|
|
|
|
text = text_buffer.get_text(start, end, False)
|
|
|
|
if text.startswith(("- ", "* ", "+ ")):
|
|
|
|
delete_end = start.copy()
|
|
|
|
delete_end.forward_chars(2)
|
|
|
|
text_buffer.delete(start, delete_end)
|
|
|
|
else:
|
|
|
|
text_buffer.insert(start, "- ")
|
2019-03-31 02:16:18 +00:00
|
|
|
else:
|
|
|
|
helptext = _("Item")
|
|
|
|
text_length = len(helptext)
|
|
|
|
|
|
|
|
cursor_mark = text_buffer.get_insert()
|
|
|
|
cursor_iter = text_buffer.get_iter_at_mark(cursor_mark)
|
|
|
|
|
|
|
|
start_ext = cursor_iter.copy()
|
|
|
|
start_ext.backward_lines(3)
|
|
|
|
text = text_buffer.get_text(cursor_iter, start_ext, False)
|
|
|
|
lines = text.splitlines()
|
|
|
|
|
2019-06-22 03:25:43 +00:00
|
|
|
with user_action(text_buffer):
|
|
|
|
for line in reversed(lines):
|
|
|
|
if line and line.startswith(("- ", "* ", "+ ")):
|
2019-03-31 02:16:18 +00:00
|
|
|
if cursor_iter.starts_line():
|
2019-06-22 03:25:43 +00:00
|
|
|
text_buffer.insert_at_cursor(line[:2] + helptext)
|
2019-03-31 02:16:18 +00:00
|
|
|
else:
|
2019-06-22 03:25:43 +00:00
|
|
|
text_buffer.insert_at_cursor("\n" + line[:2] + helptext)
|
|
|
|
break
|
2019-03-31 02:16:18 +00:00
|
|
|
else:
|
2019-06-22 03:25:43 +00:00
|
|
|
if not lines[-1] and not lines[-2]:
|
|
|
|
text_buffer.insert_at_cursor("- " + helptext)
|
|
|
|
elif not lines[-1]:
|
|
|
|
if cursor_iter.starts_line():
|
|
|
|
text_buffer.insert_at_cursor("- " + helptext)
|
|
|
|
else:
|
|
|
|
text_buffer.insert_at_cursor("\n- " + helptext)
|
|
|
|
else:
|
|
|
|
text_buffer.insert_at_cursor("\n\n- " + helptext)
|
|
|
|
break
|
2019-03-31 02:16:18 +00:00
|
|
|
|
|
|
|
self.__select_text(text_view, 0, text_length)
|
|
|
|
|
|
|
|
def insert_ordered_list_item(self, _text_view, _data=None):
|
|
|
|
# TODO: implement ordered lists
|
|
|
|
pass
|
|
|
|
|
|
|
|
def insert_header(self, text_view, _data=None):
|
|
|
|
"""Insert header or mark a selection as a list header"""
|
|
|
|
|
|
|
|
text_buffer = text_view.get_buffer()
|
2019-06-22 03:25:43 +00:00
|
|
|
with user_action(text_buffer):
|
|
|
|
if text_buffer.get_has_selection():
|
|
|
|
(start, end) = text_buffer.get_selection_bounds()
|
|
|
|
text = text_buffer.get_text(start, end, False)
|
|
|
|
text_buffer.delete(start, end)
|
|
|
|
else:
|
|
|
|
text = _("Header")
|
|
|
|
|
|
|
|
text_buffer.insert_at_cursor("#" + " " + text)
|
2019-03-31 02:16:18 +00:00
|
|
|
|
|
|
|
self.__select_text(text_view, 0, len(text))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def __wrap(text_view, wrap, helptext=""):
|
|
|
|
"""Inserts wrap format to the selected text (helper text when nothing selected)"""
|
|
|
|
text_buffer = text_view.get_buffer()
|
2019-06-22 03:25:43 +00:00
|
|
|
with user_action(text_buffer):
|
|
|
|
if text_buffer.get_has_selection():
|
|
|
|
# Find current highlighting
|
|
|
|
(start, end) = text_buffer.get_selection_bounds()
|
|
|
|
moved = False
|
|
|
|
if (start.get_offset() >= len(wrap) and
|
|
|
|
end.get_offset() <= text_buffer.get_char_count() - len(wrap)):
|
|
|
|
moved = True
|
|
|
|
ext_start = start.copy()
|
|
|
|
ext_start.backward_chars(len(wrap))
|
|
|
|
ext_end = end.copy()
|
|
|
|
ext_end.forward_chars(len(wrap))
|
|
|
|
text = text_buffer.get_text(ext_start, ext_end, True)
|
|
|
|
else:
|
|
|
|
text = text_buffer.get_text(start, end, True)
|
2019-03-31 02:16:18 +00:00
|
|
|
|
2019-06-22 03:25:43 +00:00
|
|
|
if moved and text.startswith(wrap) and text.endswith(wrap):
|
2019-03-31 02:16:18 +00:00
|
|
|
text = text[len(wrap):-len(wrap)]
|
2019-06-22 03:25:43 +00:00
|
|
|
new_text = text
|
|
|
|
text_buffer.delete(ext_start, ext_end)
|
|
|
|
move_back = 0
|
|
|
|
else:
|
|
|
|
if moved:
|
|
|
|
text = text[len(wrap):-len(wrap)]
|
|
|
|
new_text = text.lstrip().rstrip()
|
|
|
|
text = text.replace(new_text, wrap + new_text + wrap)
|
2019-03-31 02:16:18 +00:00
|
|
|
|
2019-06-22 03:25:43 +00:00
|
|
|
text_buffer.delete(start, end)
|
|
|
|
move_back = len(wrap)
|
2019-03-31 02:16:18 +00:00
|
|
|
|
2019-06-22 03:25:43 +00:00
|
|
|
text_buffer.insert_at_cursor(text)
|
|
|
|
text_length = len(new_text)
|
2019-03-31 02:16:18 +00:00
|
|
|
|
2019-06-22 03:25:43 +00:00
|
|
|
else:
|
|
|
|
text_buffer.insert_at_cursor(wrap + helptext + wrap)
|
|
|
|
text_length = len(helptext)
|
|
|
|
move_back = len(wrap)
|
2019-03-31 02:16:18 +00:00
|
|
|
|
|
|
|
cursor_mark = text_buffer.get_insert()
|
|
|
|
cursor_iter = text_buffer.get_iter_at_mark(cursor_mark)
|
|
|
|
cursor_iter.backward_chars(move_back)
|
|
|
|
text_buffer.move_mark_by_name('selection_bound', cursor_iter)
|
|
|
|
cursor_iter.backward_chars(text_length)
|
|
|
|
text_buffer.move_mark_by_name('insert', cursor_iter)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def __select_text(text_view, offset, length):
|
|
|
|
"""Selects text starting at the current cursor minus offset, length characters."""
|
|
|
|
|
|
|
|
text_buffer = text_view.get_buffer()
|
|
|
|
cursor_mark = text_buffer.get_insert()
|
|
|
|
cursor_iter = text_buffer.get_iter_at_mark(cursor_mark)
|
|
|
|
cursor_iter.backward_chars(offset)
|
|
|
|
text_buffer.move_mark_by_name('selection_bound', cursor_iter)
|
|
|
|
cursor_iter.backward_chars(length)
|
|
|
|
text_buffer.move_mark_by_name('insert', cursor_iter)
|