1# Copyright (c) 2016-2020 Hugo Osvaldo Barrera 2# Copyright (c) 2013-2016 Christian Geier et al. 3# 4# Permission is hereby granted, free of charge, to any person obtaining 5# a copy of this software and associated documentation files (the 6# "Software"), to deal in the Software without restriction, including 7# without limitation the rights to use, copy, modify, merge, publish, 8# distribute, sublicense, and/or sell copies of the Software, and to 9# permit persons to whom the Software is furnished to do so, subject to 10# the following conditions: 11# 12# The above copyright notice and this permission notice shall be 13# included in all copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22import re 23 24import click 25import urwid 26 27 28class ExtendedEdit(urwid.Edit): 29 """A text editing widget supporting some more editing commands""" 30 31 HELP = [ 32 ("Ctrl-W", "Delete word"), 33 ("Ctrl-U", "Delete until beginning of line"), 34 ("Ctrl-K", "Delete until end of line"), 35 ("Ctrl-A", "Go to beginning of line"), 36 ("Ctrl-E", "Go to end of line"), 37 ("Ctrl-D", "Delete forward letter"), 38 ("Ctrl-O", "Edit in $EDITOR"), 39 ] 40 41 def __init__(self, parent, *a, **kw): 42 self._parent = parent 43 super().__init__(*a, **kw) 44 45 def keypress(self, size, key): 46 if key == "ctrl w": 47 self._delete_word() 48 elif key == "ctrl u": 49 self._delete_till_beginning_of_line() 50 elif key == "ctrl k": 51 self._delete_till_end_of_line() 52 elif key == "ctrl a": 53 self._goto_beginning_of_line() 54 elif key == "ctrl e": 55 self._goto_end_of_line() 56 elif key == "ctrl d": 57 self._delete_forward_letter() 58 elif key == "ctrl o": 59 # Allow editing in $EDITOR 60 self._editor() 61 # TODO: alt b, alt f 62 else: 63 return super().keypress(size, key) 64 65 def _delete_forward_letter(self): 66 text = self.get_edit_text() 67 pos = self.edit_pos 68 text = text[:pos] + text[pos + 1 :] 69 self.set_edit_text(text) 70 71 def _delete_word(self): 72 """delete word before cursor""" 73 text = self.get_edit_text() 74 t = text[: self.edit_pos].rstrip() 75 76 words = re.findall(r"[\w]+|[^\w\s]", t, re.UNICODE) 77 if t == "": 78 f_text = t 79 else: 80 f_text = t[: len(t) - len(words[-1])] 81 82 self.set_edit_text(f_text + text[self.edit_pos :]) 83 self.set_edit_pos(len(f_text)) 84 85 def _delete_till_beginning_of_line(self): 86 """delete till start of line before cursor""" 87 text = self.get_edit_text() 88 sol = text.rfind("\n", 0, self.edit_pos) + 1 89 90 before_line = text[:sol] 91 92 self.set_edit_text(before_line + text[self.edit_pos :]) 93 self.set_edit_pos(sol) 94 95 def _delete_till_end_of_line(self): 96 """delete till end of line before cursor""" 97 text = self.get_edit_text() 98 eol = text.find("\n", self.edit_pos) 99 100 if eol == -1: 101 after_eol = "" 102 else: 103 after_eol = text[eol:] 104 105 self.set_edit_text(text[: self.edit_pos] + after_eol) 106 107 def _goto_beginning_of_line(self): 108 text = self.get_edit_text() 109 sol = text.rfind("\n", 0, self.edit_pos) + 1 110 self.set_edit_pos(sol) 111 112 def _goto_end_of_line(self): 113 text = self.get_edit_text() 114 eol = text.find("\n", self.edit_pos) 115 if eol == -1: 116 eol = len(text) 117 self.set_edit_pos(eol) 118 119 def _editor(self): 120 self._parent._loop.screen.clear() 121 new_text = click.edit(self.get_edit_text()) 122 if new_text is not None: 123 self.set_edit_text(new_text.strip()) 124 125 126class PrioritySelector(urwid.Button): 127 128 HELP = [ 129 ("left", "Lower Priority"), 130 ("right", "Higher Priority"), 131 ] 132 133 RANGES = [ 134 [0], 135 [9, 8, 7, 6], 136 [5], 137 [1, 2, 3, 4], 138 ] 139 140 def __init__(self, parent, priority, formatter_function): 141 self._parent = parent 142 self._label = urwid.SelectableIcon("", 0) 143 urwid.WidgetWrap.__init__(self, self._label) 144 145 self._priority = priority 146 self._formatter = formatter_function 147 self._set_label() 148 149 def _set_label(self): 150 self.set_label(self._formatter(self._priority)) 151 152 def _update_label(self, delta=0): 153 for i, r in enumerate(PrioritySelector.RANGES): 154 if self._priority in r: 155 self._priority = PrioritySelector.RANGES[ 156 (i + delta) % len(PrioritySelector.RANGES) 157 ][0] 158 self._set_label() 159 return 160 161 def keypress(self, size, key): 162 if key in ["right", "enter"]: 163 self._update_label(1) 164 return 165 if key == "left": 166 self._update_label(-1) 167 return 168 169 return super().keypress(size, key) 170 171 @property 172 def priority(self): 173 return self._priority 174