def _insert_snippet_at_node(self, leaf, snippet, new_node, line, column): self.redo_stack = [] value = leaf.value leaf_position = leaf.position if len(leaf_position) == 1: x, y = leaf_position[0] leaf_position = [(x, y), (x, y + 1)] leaf_start, leaf_end = leaf_position leaf_index = leaf.index_in_parent placeholder = snippet.placeholder text_tokens = list(placeholder.tokens) first_tokens = text_tokens[:leaf_index] second_tokens = text_tokens[leaf_index + 1:] if leaf_start == (line, column): single_token = False if len(text_tokens) == 1: possible_snippet = new_node.tokens[0] single_token = True if isinstance(possible_snippet, nodes.SnippetASTNode): # Placeholder replacement first_tokens = ( list(possible_snippet.placeholder.tokens) + list(new_node.tokens[1:]) ) second_tokens = [] else: first_tokens = list(new_node.tokens) second_tokens = [] if not single_token: if isinstance(new_node, nodes.TextNode): first_tokens += list(new_node.tokens) else: first_tokens.append(new_node) if not new_node.text().startswith(value): first_tokens.append(leaf) elif leaf_end == (line, column): first_tokens.append(leaf) first_tokens.append(new_node) else: _, start_pos = leaf_start diff = column - start_pos first_part = value[:diff] second_part = value[diff:] first_node = nodes.LeafNode(leaf.name, first_part) second_node = nodes.LeafNode(leaf.name, second_part) first_tokens.append(first_node) first_tokens.append(new_node) first_tokens.append(second_node) text_tokens = first_tokens + second_tokens placeholder.tokens = text_tokens
def _remove_selection(self, selection_start, selection_end): start_node, _, _ = self._find_node_by_position(*selection_start) end_node, _, _ = self._find_node_by_position(*selection_end) ancestor = self._find_lowest_common_ancestor(start_node, end_node) if ancestor is None: self.reset() return poly = self._region_to_polygon(selection_start, selection_end) bboxes = [sum(segment, tuple()) for segment in poly] for segment in poly: (_, start_column), (_, end_column) = segment bbox = sum(segment, tuple()) nodes_spanned = list(self.index.intersection(bbox)) current_position = start_column for node_id in nodes_spanned: _, node = self.node_position[node_id] if node.to_delete: continue if current_position >= end_column: break node_position = node.position if isinstance(node, nodes.SnippetASTNode): if len(node_position) == 1: node_position = node_position[0] node_start, node_end = node_position[0] if node_position == segment: node.placeholder.delete() node.placeholder = nodes.TextNode(nodes.LeafNode()) elif node_start == current_position: if node_end <= end_column: node.delete() node_parent = node.parent parent_tokens = list( node_parent.tokens) parent_tokens.pop(node.index_in_parent) node_parent.tokens = parent_tokens snippet_number = node.number diff = 0 for num in self.snippets_map: if num > snippet_number: snippet = self.snippets_map[num] snippet.number = snippet_number - diff diff += 1 elif isinstance(node, nodes.TextNode): if len(node_position) == 1: (node_start, node_end) = node_position[0][0] if node_start == current_position: if node_end <= end_column: node.delete() current_position = node_end if node.parent is not None: node_parent = node.parent if isinstance(node_parent, nodes.TextNode): parent_tokens = list( node.parent.tokens) parent_tokens.pop(node.index_in_parent) node_parent.tokens = parent_tokens elif isinstance(node, nodes.LeafNode): if len(node_position) == 1: leaf_line, leaf_col = node_position[0] node_position = ( (leaf_line, leaf_col), (leaf_line, leaf_col + 1)) (_, node_start), (_, node_end) = node_position if current_position == node_start: if node_end <= end_column: node_parent = node.parent parent_tokens = list(node_parent.tokens) parent_tokens.pop(node.index_in_parent) node_parent.tokens = parent_tokens current_position = node_end else: diff = end_column - node_end node_value = node.value node.value = node_value[diff:] current_position = node_start + diff elif node_start < current_position: start_diff = current_position - node_start end_diff = end_column - node_end node_value = node.value node.value = (node_value[:start_diff] + node_value[end_diff:]) current_position = ( current_position + (end_diff - start_diff)) self._update_ast()
def insert_text(self, text, line, column): has_selected_text = self.editor.has_selected_text() start, end = self.editor.get_selection_start_end() if has_selected_text: self._remove_selection(start, end) line, column = start node, snippet, text_node = self._find_node_by_position(line, column) if node is None: self.reset() return tokens = tokenize(text) token_nodes = [nodes.LeafNode(t.token, t.value) for t in tokens] for token in token_nodes: token.compute_position((line, column)) if node.name == 'EPSILON': new_text_node = nodes.TextNode(*token_nodes) snippet.placeholder = new_text_node return position = node.position if len(position) == 1: x, y = position[0] position = ((x, y), (x, y + 1)) leaf_start, leaf_end = position node_index = node.index_in_parent text_node_tokens = list(text_node.tokens) if (line, column) == leaf_start: left_offset = 0 right_offset = 0 first_token = token_nodes[0] last_token = token_nodes[-1] if node_index > 0 and len(text_node_tokens) > 1: previous_node = text_node_tokens[node_index - 1] if first_token.mark_for_position: if first_token.name in MERGE_ALLOWED: if first_token.name == previous_node.name: left_offset = 1 first_token.value = ( previous_node.value + first_token.value) if last_token.mark_for_position: if last_token.name in MERGE_ALLOWED: if last_token.name == node.name: right_offset = 1 last_token.value = ( last_token.value + node.value) text_node_tokens = ( text_node_tokens[:node_index - left_offset] + token_nodes + text_node_tokens[node_index + right_offset:] ) elif (line, column) == leaf_end: left_offset = -1 right_offset = 1 first_token = token_nodes[0] last_token = token_nodes[-1] if node_index >= 1 and node_index < len(text_node_tokens) - 1: next_node = text_node_tokens[node_index + 1] if last_token.mark_for_position: if last_token.name in MERGE_ALLOWED: if last_token.name == next_node.name: right_offset = 2 last_token.value = ( last_token.value + next_node.value) if first_token.mark_for_position: if first_token.name in MERGE_ALLOWED: if first_token.name == node.name: left_offset = 0 first_token.value = ( node.value + first_token.value) text_node_tokens = ( text_node_tokens[:node_index - left_offset] + token_nodes + text_node_tokens[node_index + right_offset:] ) else: _, start_pos = leaf_start diff = column - start_pos value = node.value first_tokens = text_node_tokens[:node_index] second_tokens = text_node_tokens[node_index + 1:] first_part = value[:diff] second_part = value[diff:] first_token = token_nodes[0] last_token = token_nodes[-1] left_merge = False if first_token.mark_for_position: if first_token.name in MERGE_ALLOWED: if first_token == node.name: left_merge = True first_token.value = first_part + first_token.value if not left_merge: first_tokens.append(nodes.LeafNode(node.name, first_part)) right_merge = False if last_token.mark_for_position: if last_token.name in MERGE_ALLOWED: if last_token == node.name: right_merge = True last_token.value = last_token.value + second_part if not right_merge: second_tokens.insert(0, nodes.LeafNode(node.name, second_part)) text_node_tokens = first_tokens + token_nodes + second_tokens text_node.tokens = text_node_tokens
def _delete_token(self, node, text_node, line, column): node_position = node.position text_node_tokens = list(text_node.tokens) node_index = node.index_in_parent if len(node_position) == 1: # Single character removal if node_index > 0 and node_index + 1 < len(text_node_tokens): left_node = text_node_tokens[node_index - 1] right_node = text_node_tokens[node_index + 1] offset = 1 if left_node.mark_for_position: if not isinstance(left_node, nodes.LeafNode): self.reset() return if left_node.name in MERGE_ALLOWED: if left_node.name == right_node.name: left_node.value = ( left_node.value + right_node.value) offset = 2 text_node_tokens = ( text_node_tokens[:node_index] + text_node_tokens[node_index + offset:] ) else: text_node_tokens.pop(node_index) else: node_start, node_end = node_position if node_start == (line, column): previous_token = text_node_tokens[node_index - 1] previous_value = previous_token.value previous_value = previous_value[:-1] merge = True diff = 0 if len(previous_value) == 0: if node_index - 2 > 0: previous_token = text_node_tokens[node_index - 2] else: merge = False text_node_tokens.pop(node_index - 1) diff = 1 else: previous_token.value = previous_value if merge: if node.mark_for_position: if node.name in MERGE_ALLOWED: if node.name == previous_token.name: previous_token.value = ( previous_token.value + node.value) text_node_tokens.pop(node_index - diff) elif node_end == (line, column): node_value = node.value node_value = node_value[:-1] if len(node_value) == 0: text_node_tokens.pop(node_index) else: node.value = node_value else: x, y = node_start diff = column - y node_value = node.value node_value = node_value[:diff] + node_value[diff + 1:] node.value = node_value if len(text_node_tokens) == 0: text_node_tokens = [nodes.LeafNode()] text_node.tokens = text_node_tokens