def do_query_data(self, start: Gtk.TextIter, end: Gtk.TextIter, state: GtkSource.GutterRendererState): view: GtkSource.View = self.get_view() buffer: GtkSource.Buffer = view.get_buffer() execution_marks = buffer.get_source_marks_at_line( start.get_line(), 'execution-line') breaked_marks = buffer.get_source_marks_at_line( start.get_line(), 'breaked-line') if len(breaked_marks) > 0: type_id = -1 slot_id = -1 if len(execution_marks) > 0: _, type_id, slot_id = EXECUTION_LINE_PATTERN.match( execution_marks[0].get_name()).groups() self.set_pixbuf( create_breaked_line_icon(int(type_id), int(slot_id), self._icon_actor, self._icon_object, self._icon_performer, self._icon_global_script)) return if len(execution_marks) > 0: _, type_id, slot_id = EXECUTION_LINE_PATTERN.match( execution_marks[0].get_name()).groups() # Don't show for global self.set_pixbuf( create_execution_line_icon(int(type_id), int(slot_id), self._icon_actor, self._icon_object, self._icon_performer, self._icon_global_script)) return self.set_pixbuf(self.empty)
def follow_if_link(self, text_view: 'LinkedTextView', itr: Gtk.TextIter) -> bool: """Retrieve the target of a link that was clicked. This is done by emitting the `link-activated` signal defined in this class. Whether or not it was a link, the click won't be processed further. """ # Get the tags where the colours are set, marking the link text. begin = itr.copy() begin.forward_to_tag_toggle() end = itr.copy() end.backward_to_tag_toggle() # Get the target of the link from its text. link_text = text_view.get_buffer().get_text(begin, end) target = text_view.get_buffer().markup_dict.get(link_text) # Confirm that is is in the links dictionary. if target is not None: self.emit('link-activated', target) return False # Do not process the signal further.
def detect_tag(self, text: str, start: Gtk.TextIter) -> None: """Detect GTGs tags and applies text tags to them.""" # Find all matches matches = re.finditer(TAG_REGEX, text) # Go through each with its own iterator and tag 'em for match in matches: tag_start = start.copy() tag_end = start.copy() tag_start.forward_chars(match.start()) tag_end.forward_chars(match.end()) # I find this confusing too :) tag_name = match.group(0) tag_name = tag_name.replace('@', '') tag_tag = TaskTagTag(tag_name, self.req) self.tags_applied.append(tag_tag) self.table.add(tag_tag) self.buffer.apply_tag(tag_tag, tag_start, tag_end) self.task_tags.add(tag_name) self.add_tasktag_cb(tag_name)
def on_sourcebuffer_delete_range(self, buffer: GtkSource.Buffer, start: Gtk.TextIter, end: Gtk.TextIter): if start.get_line() != end.get_line() or start.get_chars_in_line( ) == 0: i = start.copy() ms = [] while i.get_offset() <= end.get_offset(): ms += buffer.get_source_marks_at_iter(i, 'breakpoint') if not i.forward_char(): break for m in ms: self.remove_breakpoint(m) return True
def _build_calltip_data(self, textiter: Gtk.TextIter, buffer: GtkSource.Buffer): cursor = textiter.copy() count_commas = 0 count_commas_since_last_lang_string_begin_mark = 0 while cursor.backward_char(): if cursor.get_char() == ')': # We are not in a function, for sure! return None if cursor.get_char() == '{' or cursor.get_char() == '<': # Handle middle of language string or a pos marker count_commas -= count_commas_since_last_lang_string_begin_mark count_commas_since_last_lang_string_begin_mark = 0 if cursor.get_char() == '}' or cursor.get_char() == '>': # Handle end of language string or a pos marker count_commas_since_last_lang_string_begin_mark = 0 if cursor.get_char() == '(': # Handle the opcode/function name start_of_word = cursor.copy() backward_until_space(start_of_word) opcode_name = buffer.get_text(start_of_word, cursor, False) for op in self.opcodes: if op.name == opcode_name: return op, count_commas return None if cursor.get_char() == ',': # Collect commas for the arg index count_commas += 1 count_commas_since_last_lang_string_begin_mark += 1 return None
def follow_if_link(self, text_view: 'LinkedTimeView', itr: Gtk.TextIter) -> bool: """Looks at all tags covered by the TextIter position in the text view, and if one of them is a time link, emit a signal to display the timer """ blue = Gdk.RGBA(red=0., green=0, blue=1., alpha=1.) tags = itr.get_tags() for tag in tags: color = tag.get_property('foreground-rgba') if color and color == blue: # By Gourmet convention, only links have color start_sentence = itr.copy() start_sentence.backward_sentence_start() end_sentence = itr.copy() if not end_sentence.ends_sentence(): end_sentence.forward_sentence_end() sentence = self.get_buffer().get_slice(start_sentence, end_sentence, False) start_ts = itr.copy() start_ts.backward_to_tag_toggle(tag) itr.forward_to_tag_toggle(tag) end_ts = itr.copy() time_string = self.get_buffer().get_slice(start_ts, end_ts, False) self.emit("time-link-activated", time_string, sentence) return True return False
def detect_url(self, text: str, start: Gtk.TextIter) -> None: """Detect URLs and apply tags.""" # Find all matches matches = url_regex.search(text) # Go through each with its own iterator and tag 'em for match in matches: url_start = start.copy() url_end = start.copy() url_start.forward_chars(match.start()) url_end.forward_chars(match.end()) url_tag = LinkTag(match.group(0)) self.tags_applied.append(url_tag) self.table.add(url_tag) self.buffer.apply_tag(url_tag, url_start, url_end)
def detect_subheading(self, text: str, start: Gtk.TextIter) -> None: """Detect subheadings (akin to H2).""" if text.startswith('# ') and len(text) > 2: end = start.copy() end.forward_chars(2) invisible_tag = InvisibleTag() self.table.add(invisible_tag) self.buffer.apply_tag(invisible_tag, start, end) start.forward_chars(2) end.forward_to_line_end() subheading_tag = SubheadingTag() self.table.add(subheading_tag) self.buffer.apply_tag(subheading_tag, start, end) self.tags_applied.append(subheading_tag) self.tags_applied.append(invisible_tag)
def follow_if_link(self, text_view: 'LinkedTimeView', itr: Gtk.TextIter) -> bool: """Launch a timer if a link was clicked. This is done by emitting the `time-link-activated` signal defined in this class. Whether or not the it was a link, the click won't be processed further. """ # Get the displayed text sentence, to use as a label in the timer. start_sentence = itr.copy() start_sentence.backward_sentence_start() end_sentence = itr.copy() if not end_sentence.ends_sentence(): end_sentence.forward_sentence_end() sentence = self.get_buffer().get_slice(start_sentence, end_sentence, False) # Get the time duration (target of the link). start_ts = itr.copy() start_ts.backward_to_tag_toggle() itr.forward_to_tag_toggle() end_ts = itr.copy() time_string = self.get_buffer().get_slice(start_ts, end_ts, False) # Confirm that is is in the links dictionary. if self.get_buffer().markup_dict.get(time_string) == time_string: self.emit("time-link-activated", time_string, sentence) return False # Do not process the event further.
def detect_internal_link(self, text: str, start: Gtk.TextIter) -> None: """Detect internal links (to other gtg tasks) and apply tags.""" # Find all matches matches = re.finditer(INTERNAL_REGEX, text) # Go through each with its own iterator and tag 'em for match in matches: url_start = start.copy() url_end = start.copy() url_start.forward_chars(match.start()) url_end.forward_chars(match.end()) tid = match.group(0).replace('gtg://', '') task = self.req.get_task(tid) if task: link_tag = InternalLinkTag(task) self.tags_applied.append(link_tag) self.table.add(link_tag) self.buffer.apply_tag(link_tag, url_start, url_end)
def follow_if_link(self, text_view: 'LinkedTextView', itr: Gtk.TextIter) -> None: """Looks at all tags covering the position of iter in the text view, and if one of them is a link, follow it by showing the page identified by the data attached to it. """ blue = Gdk.RGBA(red=0, green=0, blue=1., alpha=1.) tags = itr.get_tags() for tag in tags: color = tag.get_property('foreground-rgba') if color and color == blue: begin = itr.copy() begin.forward_to_tag_toggle(tag) end = itr.copy() end.backward_to_tag_toggle(tag) link_text = text_view.get_buffer().get_text(begin, end) target = text_view.get_buffer().markup_dict[link_text] self.emit('link-activated', target) break
def extract(self, iterator: Gtk.TextIter): self._symbols.clear() symbol = [] iterator = iterator.get_buffer().get_start_iter() is_string = False for char in self._get_chars(iterator): if char == '"': is_string = not is_string if not is_string and char in SymbolsSet.SYMBOL_CHARS: symbol.append(char) elif len(symbol) > 0: self._symbols.add("".join(symbol)) symbol.clear() if len(symbol) > 0: self._symbols.add("".join(symbol))
def _get_start_pos_mark(textiter: Gtk.TextIter) -> Optional[Tuple[int, int]]: cursor: Gtk.TextIter = textiter.copy() limit = 50 i = 0 while cursor.backward_char(): if i > limit: break if cursor.get_char() == '>': # We are not in a PositionMark, for sure! return None if cursor.get_char() == 'P': # Start of position mark? end_cursor = cursor.copy() end_cursor.forward_chars(9) if cursor.get_text(end_cursor) == 'Position<': return cursor.get_line(), cursor.get_line_offset() i += 1 return None
def on_sourceview_line_mark_activated(self, widget: GtkSource.View, textiter: Gtk.TextIter, event: Gdk.Event): marks = widget.get_buffer().get_source_marks_at_iter(textiter) # Only allow editing one view. if self._explorerscript_active and widget == self._ssb_script_view: return if not self._explorerscript_active and widget == self._explorerscript_view: return # No mark? Add! if len(marks) < 1: self.add_breakpoint(textiter.get_line() + 1, widget) else: # Mark? Remove breakpoint! for mark in marks: self.remove_breakpoint(mark) return True
def add_checkbox(self, tid: int, start: Gtk.TextIter) -> None: """Add a checkbox for a subtask.""" task = self.req.get_task(tid) checkbox = Gtk.CheckButton.new() if task and task.status != task.STA_ACTIVE: checkbox.set_active(True) checkbox.connect('toggled', lambda _: self.on_checkbox_toggle(tid)) checkbox.set_can_focus(False) # Block the modified signal handler while we add the anchor # for the checkbox widget with GObject.signal_handler_block(self.buffer, self.id_modified): anchor = self.buffer.create_child_anchor(start) self.add_child_at_anchor(checkbox, anchor) end = start.copy() end.forward_char() self.buffer.apply_tag(self.checkbox_tag, start, end) self.buffer.set_modified(False) checkbox.show()
def detect_subtasks(self, text: str, start: Gtk.TextIter) -> bool: """Detect a subtask line. Returns True if a subtask was found.""" # This function has three paths: # * "Initial" Path: We find the line starts with '- ' and has text. # * "Modified" Path: We find the line starts with a subtask tag # * "None" Path: The line doesn't have any subtasks # The structure of a subtask in terms of text tags is: # <subtask> # <checkbox>[ ]</checkbox> # <internal-link>Subtask name</internal-link> # </subtask> # Add a new subtask if text.startswith('- ') and len(text[2:]) > 0: # Remove the - delete_end = start.copy() delete_end.forward_chars(2) self.buffer.delete(start, delete_end) # Add new subtask tid = self.new_subtask_cb(text[2:]) task = self.req.get_task(tid) status = task.get_status() if task else 'Active' # Add the checkbox self.add_checkbox(tid, start) after_checkbox = start.copy() after_checkbox.forward_char() # Add the internal link link_tag = InternalLinkTag(tid, status) self.table.add(link_tag) end = start.copy() end.forward_to_line_end() self.buffer.apply_tag(link_tag, after_checkbox, end) self.tags_applied.append(link_tag) # Add the subtask tag start.backward_char() subtask_tag = SubTaskTag(tid) self.table.add(subtask_tag) self.buffer.apply_tag(subtask_tag, start, end) self.subtasks['tags'].append(tid) return True # A subtask already exists elif start.starts_tag(): # Detect if it's a subtask tag sub_tag = None for tag in start.get_tags(): if type(tag) == SubTaskTag: sub_tag = tag # Otherwise return early if not sub_tag: return False # Don't auto-remove it tid = sub_tag.tid task = self.req.get_task(tid) parents = task.get_parents() # Remove if its not a child of this task if not parents or parents[0] != self.tid: log.debug('Task %s is not a subtask of %s', tid, self.tid) log.debug('Removing subtask %s from content', tid) end = start.copy() end.forward_to_line_end() # Move the start iter to take care of the newline at # the previous line start.backward_chars(2) self.buffer.delete(start, end) return False # Check that we still have a checkbox after_checkbox = start.copy() after_checkbox.forward_char() has_checkbox = any(type(t) == CheckboxTag for t in after_checkbox.get_tags()) if not has_checkbox: check = self.buffer.get_slice(start, after_checkbox, True) # Check that there's still a checkbox. If the user has # deleted all text including the space after the checkbox, # the check for the tag will return False. In this case # we want to check if the checkbox is still around, if it # is the user might still type a new name for the task. # Otherwise, if the checkbox was deleted, we return and let # the text tags be deleted. if check != u'\uFFFC': return False try: self.subtasks['to_delete'].remove(tid) except ValueError: pass self.rename_subtask_cb(tid, text) # Get the task and instantiate an internal link tag status = task.get_status() if task else 'Active' link_tag = InternalLinkTag(tid, status) self.table.add(link_tag) # Apply the new internal link tag (which was removed # by process()) end = start.copy() end.forward_to_line_end() self.buffer.apply_tag(link_tag, after_checkbox, end) self.tags_applied.append(link_tag) # Re-apply the subtask tag too self.table.remove(sub_tag) subtask_tag = SubTaskTag(tid) self.table.add(subtask_tag) self.buffer.apply_tag(subtask_tag, start, end) return True # No subtask, no fun else: return False
def detect_subtasks(self, text: str, start: Gtk.TextIter) -> bool: """Detect a subtask line. Returns True if a subtask was found.""" # This function has three paths: # * "Initial" Path: We find the line starts with '- ' and has text. # * "Modified" Path: We find the line starts with a subtask tag # * "None" Path: The line doesn't have any subtasks # The structure of a subtask in terms of text tags is: # <subtask> # <checkbox>[ ]</checkbox> # <internal-link>Subtask name</internal-link> # </subtask> # Add a new subtask if text.startswith('- ') and len(text[2:]) > 0: # Remove the - delete_end = start.copy() delete_end.forward_chars(2) self.buffer.delete(start, delete_end) # Add new subtask tid = self.new_subtask_cb(text[2:]) task = self.req.get_task(tid) status = task.get_status() if task else 'Active' # Add the checkbox self.add_checkbox(tid, start) after_checkbox = start.copy() after_checkbox.forward_char() # Add the internal link link_tag = InternalLinkTag(tid, status) self.table.add(link_tag) end = start.copy() end.forward_to_line_end() self.buffer.apply_tag(link_tag, after_checkbox, end) self.tags_applied.append(link_tag) # Add the subtask tag start.backward_char() subtask_tag = SubTaskTag(tid) self.table.add(subtask_tag) self.buffer.apply_tag(subtask_tag, start, end) self.subtasks['tags'].append(tid) return True # A subtask already exists elif start.starts_tag(): # Detect if it's a subtask tag sub_tag = None for tag in start.get_tags(): if type(tag) == SubTaskTag: sub_tag = tag # Otherwise return early if not sub_tag: return False # Check that we still have a checkbox after_checkbox = start.copy() after_checkbox.forward_char() has_checkbox = any(type(t) == CheckboxTag for t in after_checkbox.get_tags()) if not has_checkbox: return False # Don't auto-remove it tid = sub_tag.tid try: self.subtasks['to_delete'].remove(tid) except ValueError: pass self.rename_subtask_cb(tid, text) # Get the task and instantiate an internal link tag task = self.req.get_task(tid) status = task.get_status() if task else 'Active' link_tag = InternalLinkTag(tid, status) self.table.add(link_tag) # Apply the new internal link tag (which was removed # by process()) end = start.copy() end.forward_to_line_end() self.buffer.apply_tag(link_tag, after_checkbox, end) self.tags_applied.append(link_tag) # Re-apply the subtask tag too self.table.remove(sub_tag) subtask_tag = SubTaskTag(tid) self.table.add(subtask_tag) self.buffer.apply_tag(subtask_tag, start, end) return True # No subtask, no fun else: return False
def backward_until_special_char(it: Gtk.TextIter): it.backward_char() while it.get_char() not in SPECIAL_CHARS_COMPLETION_START: if not it.backward_char(): return it.forward_char()
def backward_until_space(it: Gtk.TextIter): it.backward_char() while it.get_char() not in string.whitespace: if not it.backward_char(): return it.forward_char()
def _get_chars(iterator: Gtk.TextIter): char = iterator.get_char() if char != 0: yield char while iterator.forward_char(): yield iterator.get_char()