Skip to content

Commit

Permalink
some refactoring in code folding module
Browse files Browse the repository at this point in the history
  • Loading branch information
cvfosammmm committed Sep 24, 2020
1 parent e039967 commit 1d5ebde
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 70 deletions.
79 changes: 11 additions & 68 deletions setzer/document/code_folding/code_folding.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@

import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GObject
from gi.repository import GtkSource

import setzer.document.code_folding.code_folding_viewgtk as code_folding_view
import setzer.document.code_folding.code_folding_controller as code_folding_controller
import setzer.document.code_folding.code_folding_presenter as code_folding_presenter
from setzer.helpers.observable import Observable


class CodeFolding(object):
class CodeFolding(Observable):

def __init__(self, document):
Observable.__init__(self)

self.is_enabled = False

self.folding_regions = dict()
Expand All @@ -41,17 +41,11 @@ def __init__(self, document):
self.initial_folding_regions_checked_count = 0

self.document = document
self.source_view = document.view.source_view
self.source_gutter = self.source_view.get_gutter(Gtk.TextWindowType.LEFT)
self.tag_table = self.document.source_buffer.get_tag_table()
self.view = code_folding_view.CodeFoldingView()
self.presenter = code_folding_presenter.CodeFoldingPresenter(self, self.view)
self.controller = code_folding_controller.CodeFoldingController(self, self.view)

self.source_view.get_gutter(Gtk.TextWindowType.LEFT).insert(self.view, 3)
self.source_view.connect('button-press-event', self.on_click)
self.controller = code_folding_controller.CodeFoldingController(self)

self.on_buffer_changed(self.source_view.get_buffer())
self.on_buffer_changed(self.document.get_buffer())

def enable_code_folding(self):
self.is_enabled = True
Expand All @@ -64,73 +58,23 @@ def disable_code_folding(self):
self.toggle_folding_region(region, show_region_regardless_of_state=True)
self.presenter.hide_folding_bar()

def on_buffer_changed(self, buffer):
for i in range(len(self.presenter.line_invisible), buffer.get_end_iter().get_line() + 1):
self.presenter.line_invisible[i] = False

def on_click(self, widget, event):
if self.is_enabled:
x, y = self.source_view.window_to_buffer_coords(Gtk.TextWindowType.LEFT, event.x, event.y)
if event.window == self.source_view.get_window(Gtk.TextWindowType.LEFT):
line_iter, line_top = self.source_view.get_line_at_y(y)
line_number = line_iter.get_line()
if x >= -18 and line_number in self.folding_regions:
if event.type == Gdk.EventType.BUTTON_PRESS:
self.toggle_folding_region(self.folding_regions[line_number])
return True
return False

def toggle_folding_region(self, region, show_region_regardless_of_state=False, hide_region_regardless_of_state=False):
if show_region_regardless_of_state:
is_folded = False
elif hide_region_regardless_of_state:
is_folded = True
else:
is_folded = not region['is_folded']
source_buffer = self.document.source_buffer
region_id = region['id']
tag = self.get_invisible_region_tag(region_id)

if is_folded:
mark_start = region['mark_start']
start_iter = source_buffer.get_iter_at_mark(mark_start)
mark_end = region['mark_end']
end_iter = source_buffer.get_iter_at_mark(mark_end)
end_iter.forward_char()
source_buffer.apply_tag(tag, start_iter, end_iter)
else:
start_iter = source_buffer.get_start_iter()
end_iter = source_buffer.get_end_iter()
source_buffer.remove_tag(tag, start_iter, end_iter)
self.delete_invisible_region_tag(region_id)

region['is_folded'] = is_folded
self.update_line_invisibility()
self.source_gutter.queue_draw()
self.add_change_code('folding_state_changed', region)

def get_invisible_region_tag(self, region_id):
tag = self.tag_table.lookup('invisible_region_' + str(region_id))
if tag == None:
tag = self.document.source_buffer.create_tag('invisible_region_' + str(region_id), invisible=1)
return tag

def delete_invisible_region_tag(self, region_id):
tag = self.tag_table.lookup('invisible_region_' + str(region_id))
if tag != None:
self.tag_table.remove(tag)
def on_buffer_changed(self, buffer):
for i in range(len(self.presenter.line_invisible), buffer.get_end_iter().get_line() + 1):
self.presenter.line_invisible[i] = False

def get_folding_region_by_region_id(self, region_id):
return self.folding_regions_by_region_id[region_id]

def update_line_invisibility(self):
source_buffer = self.document.source_buffer
for i in range(len(self.presenter.line_invisible)):
self.presenter.line_invisible[i] = False
for region in self.folding_regions.values():
if region['is_folded']:
for line in range(region['starting_line'] + 1, region['ending_line'] + 1):
self.presenter.line_invisible[line] = True

def update_folding_regions(self):
folding_regions = dict()
folding_regions_by_region_id = dict()
Expand Down Expand Up @@ -179,8 +123,7 @@ def update_folding_regions(self):
if not self.initial_folding_done:
self.initial_folding()
else:
self.update_line_invisibility()
self.source_gutter.queue_draw()
self.presenter.update_line_visibility()

return self.is_enabled

Expand Down
23 changes: 21 additions & 2 deletions setzer/document/code_folding/code_folding_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk

from setzer.app.service_locator import ServiceLocator


class CodeFoldingController(object):

def __init__(self, model, view):
def __init__(self, model):
self.model = model
self.view = view
self.source_view = self.model.document.view.source_view
self.settings = ServiceLocator.get_settings()

if self.settings.get_value('preferences', 'enable_code_folding'):
Expand All @@ -31,6 +36,20 @@ def __init__(self, model, view):
self.model.disable_code_folding()
self.settings.register_observer(self)

self.source_view.connect('button-press-event', self.on_click)

def on_click(self, widget, event):
if self.model.is_enabled:
x, y = self.source_view.window_to_buffer_coords(Gtk.TextWindowType.LEFT, event.x, event.y)
if event.window == self.source_view.get_window(Gtk.TextWindowType.LEFT):
line_iter, line_top = self.source_view.get_line_at_y(y)
line_number = line_iter.get_line()
if x >= -18 and line_number in self.model.folding_regions:
if event.type == Gdk.EventType.BUTTON_PRESS:
self.model.toggle_folding_region(self.model.folding_regions[line_number])
return True
return False

def change_notification(self, change_code, notifying_object, parameter):

if change_code == 'settings_changed':
Expand Down
70 changes: 70 additions & 0 deletions setzer/document/code_folding/code_folding_presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,86 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk


class CodeFoldingPresenter(object):

def __init__(self, model, view):
self.model = model
self.view = view
self.source_gutter = self.model.document.view.source_view.get_gutter(Gtk.TextWindowType.LEFT)

self.tag_table = self.model.document.source_buffer.get_tag_table()
self.line_invisible = dict()

self.source_gutter.insert(self.view, 3)
self.view.connect('query-data', self.query_data)
self.model.register_observer(self)

def change_notification(self, change_code, notifying_object, parameter):

if change_code == 'is_enabled_changed':
if self.model.is_enabled:
self.show_folding_bar()
else:
self.hide_folding_bar()

if change_code == 'buffer_changed':
buffer = parameter
for i in range(len(self.line_invisible), buffer.get_end_iter().get_line() + 1):
self.line_invisible[i] = False

if change_code == 'folding_regions_updated':
self.update_line_visibility()

if change_code == 'folding_state_changed':
if parameter['is_folded']:
self.hide_region(parameter)
else:
self.show_region(parameter)

def show_region(self, region):
tag = self.get_invisible_region_tag(region['id'])
source_buffer = self.model.document.source_buffer
start_iter = source_buffer.get_start_iter()
end_iter = source_buffer.get_end_iter()
source_buffer.remove_tag(tag, start_iter, end_iter)
self.delete_invisible_region_tag(region['id'])
self.update_line_visibility()

def hide_region(self, region):
tag = self.get_invisible_region_tag(region['id'])
source_buffer = self.model.document.source_buffer
mark_start = region['mark_start']
start_iter = source_buffer.get_iter_at_mark(mark_start)
mark_end = region['mark_end']
end_iter = source_buffer.get_iter_at_mark(mark_end)
end_iter.forward_char()
source_buffer.apply_tag(tag, start_iter, end_iter)
self.update_line_visibility()

def get_invisible_region_tag(self, region_id):
tag = self.tag_table.lookup('invisible_region_' + str(region_id))
if tag == None:
tag = self.model.document.source_buffer.create_tag('invisible_region_' + str(region_id), invisible=1)
return tag

def delete_invisible_region_tag(self, region_id):
tag = self.tag_table.lookup('invisible_region_' + str(region_id))
if tag != None:
self.tag_table.remove(tag)

def update_line_visibility(self):
for i in range(len(self.line_invisible)):
self.line_invisible[i] = False
for region in self.model.folding_regions.values():
if region['is_folded']:
for line in range(region['starting_line'] + 1, region['ending_line'] + 1):
self.line_invisible[line] = True
self.source_gutter.queue_draw()

def query_data(self, renderer, start_iter, end_iter, state):
if self.line_invisible[start_iter.get_line()]: return
Expand Down

0 comments on commit 1d5ebde

Please sign in to comment.