Fix all flake8 errors
This commit is contained in:
parent
362c59f150
commit
8d25396f68
|
@ -0,0 +1,6 @@
|
||||||
|
[flake8]
|
||||||
|
builtins = _
|
||||||
|
max-line-length = 100
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
exclude = src/diffuse/main.py
|
|
@ -19,17 +19,14 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
from diffuse import constants
|
||||||
|
from diffuse import utils
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('GObject', '2.0')
|
gi.require_version('GObject', '2.0')
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import GObject, Gtk
|
from gi.repository import GObject, Gtk # noqa: E402
|
||||||
# pylint: enable=wrong-import-position
|
|
||||||
|
|
||||||
# pylint: disable-next=no-name-in-module
|
|
||||||
from diffuse import constants
|
|
||||||
|
|
||||||
from diffuse import utils
|
|
||||||
|
|
||||||
# the about dialog
|
# the about dialog
|
||||||
class AboutDialog(Gtk.AboutDialog):
|
class AboutDialog(Gtk.AboutDialog):
|
||||||
|
@ -41,8 +38,8 @@ class AboutDialog(Gtk.AboutDialog):
|
||||||
self.set_comments(_('Diffuse is a graphical tool for merging and comparing text files.'))
|
self.set_comments(_('Diffuse is a graphical tool for merging and comparing text files.'))
|
||||||
self.set_copyright(constants.COPYRIGHT)
|
self.set_copyright(constants.COPYRIGHT)
|
||||||
self.set_website(constants.WEBSITE)
|
self.set_website(constants.WEBSITE)
|
||||||
self.set_authors([ 'Derrick Moser <derrick_moser@yahoo.com>',
|
self.set_authors(['Derrick Moser <derrick_moser@yahoo.com>',
|
||||||
'Romain Failliot <romain.failliot@foolstep.com>' ])
|
'Romain Failliot <romain.failliot@foolstep.com>'])
|
||||||
self.set_translator_credits(_('translator-credits'))
|
self.set_translator_credits(_('translator-credits'))
|
||||||
license_text = [
|
license_text = [
|
||||||
constants.APP_NAME + ' ' + constants.VERSION + '\n\n',
|
constants.APP_NAME + ' ' + constants.VERSION + '\n\n',
|
||||||
|
@ -59,9 +56,10 @@ GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.''') ]
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.''')]
|
||||||
self.set_license(''.join(license_text))
|
self.set_license(''.join(license_text))
|
||||||
|
|
||||||
|
|
||||||
# custom dialogue for picking files with widgets for specifying the encoding
|
# custom dialogue for picking files with widgets for specifying the encoding
|
||||||
# and revision
|
# and revision
|
||||||
class FileChooserDialog(Gtk.FileChooserDialog):
|
class FileChooserDialog(Gtk.FileChooserDialog):
|
||||||
|
@ -85,7 +83,7 @@ class FileChooserDialog(Gtk.FileChooserDialog):
|
||||||
label.show()
|
label.show()
|
||||||
self.encoding = entry = utils.EncodingMenu(
|
self.encoding = entry = utils.EncodingMenu(
|
||||||
prefs,
|
prefs,
|
||||||
action in [ Gtk.FileChooserAction.OPEN, Gtk.FileChooserAction.SELECT_FOLDER ])
|
action in [Gtk.FileChooserAction.OPEN, Gtk.FileChooserAction.SELECT_FOLDER])
|
||||||
hbox.pack_start(entry, False, False, 5)
|
hbox.pack_start(entry, False, False, 5)
|
||||||
entry.show()
|
entry.show()
|
||||||
if rev:
|
if rev:
|
||||||
|
@ -96,7 +94,7 @@ class FileChooserDialog(Gtk.FileChooserDialog):
|
||||||
hbox.pack_end(label, False, False, 0)
|
hbox.pack_end(label, False, False, 0)
|
||||||
label.show()
|
label.show()
|
||||||
|
|
||||||
self.vbox.pack_start(hbox, False, False, 0) # pylint: disable=no-member
|
self.vbox.pack_start(hbox, False, False, 0)
|
||||||
hbox.show()
|
hbox.show()
|
||||||
self.set_current_folder(self.last_chosen_folder)
|
self.set_current_folder(self.last_chosen_folder)
|
||||||
self.connect('current-folder-changed', self._current_folder_changed_cb)
|
self.connect('current-folder-changed', self._current_folder_changed_cb)
|
||||||
|
@ -110,10 +108,10 @@ class FileChooserDialog(Gtk.FileChooserDialog):
|
||||||
def get_revision(self):
|
def get_revision(self):
|
||||||
return self.revision.get_text()
|
return self.revision.get_text()
|
||||||
|
|
||||||
# pylint: disable-next=arguments-differ
|
|
||||||
def get_filename(self):
|
def get_filename(self):
|
||||||
# convert from UTF-8 string to unicode
|
# convert from UTF-8 string to unicode
|
||||||
return Gtk.FileChooserDialog.get_filename(self) # pylint: disable=no-member
|
return Gtk.FileChooserDialog.get_filename(self)
|
||||||
|
|
||||||
|
|
||||||
# dialogue used to search for text
|
# dialogue used to search for text
|
||||||
class NumericDialog(Gtk.Dialog):
|
class NumericDialog(Gtk.Dialog):
|
||||||
|
@ -138,12 +136,13 @@ class NumericDialog(Gtk.Dialog):
|
||||||
vbox.pack_start(hbox, True, True, 0)
|
vbox.pack_start(hbox, True, True, 0)
|
||||||
hbox.show()
|
hbox.show()
|
||||||
|
|
||||||
self.vbox.pack_start(vbox, False, False, 0) # pylint: disable=no-member
|
self.vbox.pack_start(vbox, False, False, 0)
|
||||||
vbox.show()
|
vbox.show()
|
||||||
|
|
||||||
def button_cb(self, widget):
|
def button_cb(self, widget):
|
||||||
self.response(Gtk.ResponseType.ACCEPT)
|
self.response(Gtk.ResponseType.ACCEPT)
|
||||||
|
|
||||||
|
|
||||||
# dialogue used to search for text
|
# dialogue used to search for text
|
||||||
class SearchDialog(Gtk.Dialog):
|
class SearchDialog(Gtk.Dialog):
|
||||||
def __init__(self, parent, pattern=None, history=None):
|
def __init__(self, parent, pattern=None, history=None):
|
||||||
|
@ -190,7 +189,7 @@ class SearchDialog(Gtk.Dialog):
|
||||||
vbox.pack_start(button, False, False, 0)
|
vbox.pack_start(button, False, False, 0)
|
||||||
button.show()
|
button.show()
|
||||||
|
|
||||||
self.vbox.pack_start(vbox, False, False, 0) # pylint: disable=no-member
|
self.vbox.pack_start(vbox, False, False, 0)
|
||||||
vbox.show()
|
vbox.show()
|
||||||
|
|
||||||
# callback used when the Enter key is pressed
|
# callback used when the Enter key is pressed
|
||||||
|
|
|
@ -25,22 +25,9 @@ import shlex
|
||||||
import stat
|
import stat
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
|
||||||
import gi
|
|
||||||
gi.require_version('GObject', '2.0')
|
|
||||||
gi.require_version('Gtk', '3.0')
|
|
||||||
gi.require_version('Gdk', '3.0')
|
|
||||||
gi.require_version('GdkPixbuf', '2.0')
|
|
||||||
gi.require_version('Pango', '1.0')
|
|
||||||
gi.require_version('PangoCairo', '1.0')
|
|
||||||
from gi.repository import GObject, Gtk, Gdk, GdkPixbuf, Pango, PangoCairo
|
|
||||||
# pylint: enable=wrong-import-position
|
|
||||||
|
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
# pylint: disable-next=no-name-in-module
|
|
||||||
from diffuse import constants
|
from diffuse import constants
|
||||||
|
|
||||||
from diffuse import utils
|
from diffuse import utils
|
||||||
from diffuse.dialogs import AboutDialog, FileChooserDialog, NumericDialog, SearchDialog
|
from diffuse.dialogs import AboutDialog, FileChooserDialog, NumericDialog, SearchDialog
|
||||||
from diffuse.preferences import Preferences
|
from diffuse.preferences import Preferences
|
||||||
|
@ -49,6 +36,16 @@ from diffuse.vcs.vcs_registry import VcsRegistry
|
||||||
from diffuse.widgets import FileDiffViewer
|
from diffuse.widgets import FileDiffViewer
|
||||||
from diffuse.widgets import createMenu, LINE_MODE, CHAR_MODE, ALIGN_MODE
|
from diffuse.widgets import createMenu, LINE_MODE, CHAR_MODE, ALIGN_MODE
|
||||||
|
|
||||||
|
import gi
|
||||||
|
gi.require_version('GObject', '2.0')
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
gi.require_version('Gdk', '3.0')
|
||||||
|
gi.require_version('GdkPixbuf', '2.0')
|
||||||
|
gi.require_version('Pango', '1.0')
|
||||||
|
gi.require_version('PangoCairo', '1.0')
|
||||||
|
from gi.repository import GObject, Gtk, Gdk, GdkPixbuf, Pango, PangoCairo # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
theVCSs = VcsRegistry()
|
theVCSs = VcsRegistry()
|
||||||
|
|
||||||
# widget classed to create notebook tabs with labels and a close button
|
# widget classed to create notebook tabs with labels and a close button
|
||||||
|
@ -120,10 +117,10 @@ class Diffuse(Gtk.Window):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Gtk.Box.__init__(self, orientation = Gtk.Orientation.HORIZONTAL, spacing = 0)
|
Gtk.Box.__init__(self, orientation = Gtk.Orientation.HORIZONTAL, spacing = 0)
|
||||||
_append_buttons(self, Gtk.IconSize.MENU, [
|
_append_buttons(self, Gtk.IconSize.MENU, [
|
||||||
[ Gtk.STOCK_OPEN, self.button_cb, 'open', _('Open File...') ],
|
[Gtk.STOCK_OPEN, self.button_cb, 'open', _('Open File...')],
|
||||||
[ Gtk.STOCK_REFRESH, self.button_cb, 'reload', _('Reload File') ],
|
[Gtk.STOCK_REFRESH, self.button_cb, 'reload', _('Reload File')],
|
||||||
[ Gtk.STOCK_SAVE, self.button_cb, 'save', _('Save File') ],
|
[Gtk.STOCK_SAVE, self.button_cb, 'save', _('Save File')],
|
||||||
[ Gtk.STOCK_SAVE_AS, self.button_cb, 'save_as', _('Save File As...') ] ])
|
[Gtk.STOCK_SAVE_AS, self.button_cb, 'save_as', _('Save File As...') ]])
|
||||||
|
|
||||||
self.label = label = Gtk.Label.new()
|
self.label = label = Gtk.Label.new()
|
||||||
label.set_selectable(True)
|
label.set_selectable(True)
|
||||||
|
@ -258,7 +255,7 @@ class Diffuse(Gtk.Window):
|
||||||
self.connect('format-changed', self.format_changed_cb)
|
self.connect('format-changed', self.format_changed_cb)
|
||||||
|
|
||||||
for i, darea in enumerate(self.dareas):
|
for i, darea in enumerate(self.dareas):
|
||||||
darea.drag_dest_set(Gtk.DestDefaults.ALL, [ Gtk.TargetEntry.new('text/uri-list', 0, 0) ], Gdk.DragAction.COPY)
|
darea.drag_dest_set(Gtk.DestDefaults.ALL, [Gtk.TargetEntry.new('text/uri-list', 0, 0)], Gdk.DragAction.COPY)
|
||||||
darea.connect('drag-data-received', self.drag_data_received_cb, i)
|
darea.connect('drag-data-received', self.drag_data_received_cb, i)
|
||||||
# initialise status
|
# initialise status
|
||||||
self.updateStatus()
|
self.updateStatus()
|
||||||
|
@ -749,7 +746,7 @@ class Diffuse(Gtk.Window):
|
||||||
[],
|
[],
|
||||||
[_('Pr_eferences...'), self.preferences_cb, None, Gtk.STOCK_PREFERENCES, 'preferences'] ] ])
|
[_('Pr_eferences...'), self.preferences_cb, None, Gtk.STOCK_PREFERENCES, 'preferences'] ] ])
|
||||||
|
|
||||||
submenudef = [ [_('None'), self.syntax_cb, None, None, 'no_syntax_highlighting', True, None, ('syntax', None) ] ]
|
submenudef = [[_('None'), self.syntax_cb, None, None, 'no_syntax_highlighting', True, None, ('syntax', None) ]]
|
||||||
names = theResources.getSyntaxNames()
|
names = theResources.getSyntaxNames()
|
||||||
if len(names) > 0:
|
if len(names) > 0:
|
||||||
submenudef.append([])
|
submenudef.append([])
|
||||||
|
@ -820,28 +817,28 @@ class Diffuse(Gtk.Window):
|
||||||
# create button bar
|
# create button bar
|
||||||
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||||
_append_buttons(hbox, Gtk.IconSize.LARGE_TOOLBAR, [
|
_append_buttons(hbox, Gtk.IconSize.LARGE_TOOLBAR, [
|
||||||
[ DIFFUSE_STOCK_NEW_2WAY_MERGE, self.new_2_way_file_merge_cb, None, _('New 2-Way File Merge') ],
|
[DIFFUSE_STOCK_NEW_2WAY_MERGE, self.new_2_way_file_merge_cb, None, _('New 2-Way File Merge')],
|
||||||
[ DIFFUSE_STOCK_NEW_3WAY_MERGE, self.new_3_way_file_merge_cb, None, _('New 3-Way File Merge') ],
|
[DIFFUSE_STOCK_NEW_3WAY_MERGE, self.new_3_way_file_merge_cb, None, _('New 3-Way File Merge')],
|
||||||
[],
|
[],
|
||||||
[ Gtk.STOCK_EXECUTE, self.button_cb, 'realign_all', _('Realign All') ],
|
[Gtk.STOCK_EXECUTE, self.button_cb, 'realign_all', _('Realign All')],
|
||||||
[ Gtk.STOCK_GOTO_TOP, self.button_cb, 'first_difference', _('First Difference') ],
|
[Gtk.STOCK_GOTO_TOP, self.button_cb, 'first_difference', _('First Difference')],
|
||||||
[ Gtk.STOCK_GO_UP, self.button_cb, 'previous_difference', _('Previous Difference') ],
|
[Gtk.STOCK_GO_UP, self.button_cb, 'previous_difference', _('Previous Difference')],
|
||||||
[ Gtk.STOCK_GO_DOWN, self.button_cb, 'next_difference', _('Next Difference') ],
|
[Gtk.STOCK_GO_DOWN, self.button_cb, 'next_difference', _('Next Difference')],
|
||||||
[ Gtk.STOCK_GOTO_BOTTOM, self.button_cb, 'last_difference', _('Last Difference') ],
|
[Gtk.STOCK_GOTO_BOTTOM, self.button_cb, 'last_difference', _('Last Difference')],
|
||||||
[],
|
[],
|
||||||
[ Gtk.STOCK_GOTO_LAST, self.button_cb, 'copy_selection_right', _('Copy Selection Right') ],
|
[Gtk.STOCK_GOTO_LAST, self.button_cb, 'copy_selection_right', _('Copy Selection Right')],
|
||||||
[ Gtk.STOCK_GOTO_FIRST, self.button_cb, 'copy_selection_left', _('Copy Selection Left') ],
|
[Gtk.STOCK_GOTO_FIRST, self.button_cb, 'copy_selection_left', _('Copy Selection Left')],
|
||||||
[ Gtk.STOCK_GO_FORWARD, self.button_cb, 'copy_left_into_selection', _('Copy Left Into Selection') ],
|
[Gtk.STOCK_GO_FORWARD, self.button_cb, 'copy_left_into_selection', _('Copy Left Into Selection')],
|
||||||
[ Gtk.STOCK_GO_BACK, self.button_cb, 'copy_right_into_selection', _('Copy Right Into Selection') ],
|
[Gtk.STOCK_GO_BACK, self.button_cb, 'copy_right_into_selection', _('Copy Right Into Selection')],
|
||||||
[ DIFFUSE_STOCK_LEFT_RIGHT, self.button_cb, 'merge_from_left_then_right', _('Merge From Left Then Right') ],
|
[DIFFUSE_STOCK_LEFT_RIGHT, self.button_cb, 'merge_from_left_then_right', _('Merge From Left Then Right')],
|
||||||
[ DIFFUSE_STOCK_RIGHT_LEFT, self.button_cb, 'merge_from_right_then_left', _('Merge From Right Then Left') ],
|
[DIFFUSE_STOCK_RIGHT_LEFT, self.button_cb, 'merge_from_right_then_left', _('Merge From Right Then Left')],
|
||||||
[],
|
[],
|
||||||
[ Gtk.STOCK_UNDO, self.button_cb, 'undo', _('Undo') ],
|
[Gtk.STOCK_UNDO, self.button_cb, 'undo', _('Undo')],
|
||||||
[ Gtk.STOCK_REDO, self.button_cb, 'redo', _('Redo') ],
|
[Gtk.STOCK_REDO, self.button_cb, 'redo', _('Redo')],
|
||||||
[ Gtk.STOCK_CUT, self.button_cb, 'cut', _('Cut') ],
|
[Gtk.STOCK_CUT, self.button_cb, 'cut', _('Cut')],
|
||||||
[ Gtk.STOCK_COPY, self.button_cb, 'copy', _('Copy') ],
|
[Gtk.STOCK_COPY, self.button_cb, 'copy', _('Copy')],
|
||||||
[ Gtk.STOCK_PASTE, self.button_cb, 'paste', _('Paste') ],
|
[Gtk.STOCK_PASTE, self.button_cb, 'paste', _('Paste')],
|
||||||
[ Gtk.STOCK_CLEAR, self.button_cb, 'clear_edits', _('Clear Edits') ] ])
|
[Gtk.STOCK_CLEAR, self.button_cb, 'clear_edits', _('Clear Edits') ]])
|
||||||
# avoid the button bar from dictating the minimum window size
|
# avoid the button bar from dictating the minimum window size
|
||||||
hbox.set_size_request(0, hbox.get_size_request()[1])
|
hbox.set_size_request(0, hbox.get_size_request()[1])
|
||||||
vbox.pack_start(hbox, False, False, 0)
|
vbox.pack_start(hbox, False, False, 0)
|
||||||
|
@ -986,7 +983,7 @@ class Diffuse(Gtk.Window):
|
||||||
treeview.connect('row-activated', self._confirmClose_row_activated_cb, model)
|
treeview.connect('row-activated', self._confirmClose_row_activated_cb, model)
|
||||||
sw.add(treeview)
|
sw.add(treeview)
|
||||||
treeview.show()
|
treeview.show()
|
||||||
dialog.vbox.pack_start(sw, True, True, 0) # pylint: disable=no-member
|
dialog.vbox.pack_start(sw, True, True, 0)
|
||||||
sw.show()
|
sw.show()
|
||||||
# add custom set of action buttons
|
# add custom set of action buttons
|
||||||
dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
|
dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
|
||||||
|
@ -1017,7 +1014,7 @@ class Diffuse(Gtk.Window):
|
||||||
nb = self.notebook
|
nb = self.notebook
|
||||||
if nb.get_n_pages() > 1:
|
if nb.get_n_pages() > 1:
|
||||||
# warn about losing unsaved changes before removing a tab
|
# warn about losing unsaved changes before removing a tab
|
||||||
if self.confirmCloseViewers([ data ]):
|
if self.confirmCloseViewers([data]):
|
||||||
self.closed_tabs.append((nb.page_num(data), data, nb.get_tab_label(data)))
|
self.closed_tabs.append((nb.page_num(data), data, nb.get_tab_label(data)))
|
||||||
nb.remove(data)
|
nb.remove(data)
|
||||||
nb.set_show_tabs(self.prefs.getBool('tabs_always_show') or nb.get_n_pages() > 1)
|
nb.set_show_tabs(self.prefs.getBool('tabs_always_show') or nb.get_n_pages() > 1)
|
||||||
|
@ -1180,9 +1177,9 @@ class Diffuse(Gtk.Window):
|
||||||
# create a new viewer for each item in 'items'
|
# create a new viewer for each item in 'items'
|
||||||
def createSeparateTabs(self, items, labels, options):
|
def createSeparateTabs(self, items, labels, options):
|
||||||
# all tabs inherit the first tab's revision and encoding specifications
|
# all tabs inherit the first tab's revision and encoding specifications
|
||||||
items = [ (name, items[0][1]) for name, data in items ]
|
items = [(name, items[0][1]) for name, data in items]
|
||||||
for item in _assign_file_labels(items, labels):
|
for item in _assign_file_labels(items, labels):
|
||||||
self.newLoadedFileDiffViewer([ item ]).setOptions(options)
|
self.newLoadedFileDiffViewer([item]).setOptions(options)
|
||||||
|
|
||||||
# create a new viewer for each modified file found in 'items'
|
# create a new viewer for each modified file found in 'items'
|
||||||
def createCommitFileTabs(self, items, labels, options):
|
def createCommitFileTabs(self, items, labels, options):
|
||||||
|
@ -1196,7 +1193,7 @@ class Diffuse(Gtk.Window):
|
||||||
if dn == old_dn:
|
if dn == old_dn:
|
||||||
break
|
break
|
||||||
if len(new_items) == 0 or dn != new_items[-1][0]:
|
if len(new_items) == 0 or dn != new_items[-1][0]:
|
||||||
new_items.append([ dn, None, [] ])
|
new_items.append([dn, None, []])
|
||||||
dst = new_items[-1]
|
dst = new_items[-1]
|
||||||
dst[1] = data[-1][1]
|
dst[1] = data[-1][1]
|
||||||
dst[2].append(name)
|
dst[2].append(name)
|
||||||
|
@ -1225,7 +1222,7 @@ class Diffuse(Gtk.Window):
|
||||||
if dn == old_dn:
|
if dn == old_dn:
|
||||||
break
|
break
|
||||||
if len(new_items) == 0 or dn != new_items[-1][0]:
|
if len(new_items) == 0 or dn != new_items[-1][0]:
|
||||||
new_items.append([ dn, None, [] ])
|
new_items.append([dn, None, []])
|
||||||
dst = new_items[-1]
|
dst = new_items[-1]
|
||||||
dst[1] = data[-1][1]
|
dst[1] = data[-1][1]
|
||||||
dst[2].append(name)
|
dst[2].append(name)
|
||||||
|
@ -1251,7 +1248,7 @@ class Diffuse(Gtk.Window):
|
||||||
# returns True if the application can safely quit
|
# returns True if the application can safely quit
|
||||||
def confirmQuit(self):
|
def confirmQuit(self):
|
||||||
nb = self.notebook
|
nb = self.notebook
|
||||||
return self.confirmCloseViewers([ nb.get_nth_page(i) for i in range(nb.get_n_pages()) ])
|
return self.confirmCloseViewers([nb.get_nth_page(i) for i in range(nb.get_n_pages())])
|
||||||
|
|
||||||
# respond to close window request from the window manager
|
# respond to close window request from the window manager
|
||||||
def delete_cb(self, widget, event):
|
def delete_cb(self, widget, event):
|
||||||
|
@ -1279,7 +1276,7 @@ class Diffuse(Gtk.Window):
|
||||||
rev = None
|
rev = None
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
if accept:
|
if accept:
|
||||||
viewer = self.newLoadedFileDiffViewer([ (name, [ (rev, encoding) ], None) ])
|
viewer = self.newLoadedFileDiffViewer([(name, [(rev, encoding)], None)])
|
||||||
self.notebook.set_current_page(self.notebook.get_n_pages() - 1)
|
self.notebook.set_current_page(self.notebook.get_n_pages() - 1)
|
||||||
viewer.grab_focus()
|
viewer.grab_focus()
|
||||||
|
|
||||||
|
@ -1293,7 +1290,7 @@ class Diffuse(Gtk.Window):
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
if accept:
|
if accept:
|
||||||
n = self.notebook.get_n_pages()
|
n = self.notebook.get_n_pages()
|
||||||
self.createModifiedFileTabs([ (name, [ (None, encoding) ]) ], [], {})
|
self.createModifiedFileTabs([(name, [(None, encoding)])], [], {})
|
||||||
if self.notebook.get_n_pages() > n:
|
if self.notebook.get_n_pages() > n:
|
||||||
# we added some new tabs, focus on the first one
|
# we added some new tabs, focus on the first one
|
||||||
self.notebook.set_current_page(n)
|
self.notebook.set_current_page(n)
|
||||||
|
@ -1311,7 +1308,7 @@ class Diffuse(Gtk.Window):
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
if accept:
|
if accept:
|
||||||
n = self.notebook.get_n_pages()
|
n = self.notebook.get_n_pages()
|
||||||
self.createCommitFileTabs([ (name, [ (None, encoding) ]) ], [], { 'commit': rev })
|
self.createCommitFileTabs([(name, [(None, encoding)])], [], { 'commit': rev })
|
||||||
if self.notebook.get_n_pages() > n:
|
if self.notebook.get_n_pages() > n:
|
||||||
# we added some new tabs, focus on the first one
|
# we added some new tabs, focus on the first one
|
||||||
self.notebook.set_current_page(n)
|
self.notebook.set_current_page(n)
|
||||||
|
@ -1488,9 +1485,9 @@ class Diffuse(Gtk.Window):
|
||||||
if utils.isWindows():
|
if utils.isWindows():
|
||||||
# help documentation is distributed as local HTML files
|
# help documentation is distributed as local HTML files
|
||||||
# search for localised manual first
|
# search for localised manual first
|
||||||
parts = [ 'manual' ]
|
parts = ['manual']
|
||||||
if utils.lang is not None:
|
if utils.lang is not None:
|
||||||
parts = [ 'manual' ]
|
parts = ['manual']
|
||||||
parts.extend(utils.lang.split('_'))
|
parts.extend(utils.lang.split('_'))
|
||||||
while len(parts) > 0:
|
while len(parts) > 0:
|
||||||
help_file = os.path.join(utils.bin_dir, '_'.join(parts) + '.html')
|
help_file = os.path.join(utils.bin_dir, '_'.join(parts) + '.html')
|
||||||
|
@ -1524,7 +1521,7 @@ class Diffuse(Gtk.Window):
|
||||||
d = 'C'
|
d = 'C'
|
||||||
help_file = os.path.join(os.path.join(s, d), 'diffuse.xml')
|
help_file = os.path.join(os.path.join(s, d), 'diffuse.xml')
|
||||||
if os.path.isfile(help_file):
|
if os.path.isfile(help_file):
|
||||||
args = [ browser, _path2url(help_file, 'ghelp') ]
|
args = [browser, _path2url(help_file, 'ghelp')]
|
||||||
# spawnvp is not available on some systems, use spawnv instead
|
# spawnvp is not available on some systems, use spawnv instead
|
||||||
os.spawnv(os.P_NOWAIT, args[0], args)
|
os.spawnv(os.P_NOWAIT, args[0], args)
|
||||||
return
|
return
|
||||||
|
@ -1582,7 +1579,7 @@ def _append_buttons(box, size, specs):
|
||||||
|
|
||||||
# constructs a full URL for the named file
|
# constructs a full URL for the named file
|
||||||
def _path2url(path, proto='file'):
|
def _path2url(path, proto='file'):
|
||||||
r = [ proto, ':///' ]
|
r = [proto, ':///']
|
||||||
s = os.path.abspath(path)
|
s = os.path.abspath(path)
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(s) and s[i] == os.sep:
|
while i < len(s) and s[i] == os.sep:
|
||||||
|
@ -1626,11 +1623,11 @@ def main():
|
||||||
args = sys.argv
|
args = sys.argv
|
||||||
argc = len(args)
|
argc = len(args)
|
||||||
|
|
||||||
if argc == 2 and args[1] in [ '-v', '--version' ]:
|
if argc == 2 and args[1] in ['-v', '--version']:
|
||||||
print('%s %s\n%s' % (constants.APP_NAME, constants.VERSION, constants.COPYRIGHT))
|
print('%s %s\n%s' % (constants.APP_NAME, constants.VERSION, constants.COPYRIGHT))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if argc == 2 and args[1] in [ '-h', '-?', '--help' ]:
|
if argc == 2 and args[1] in ['-h', '-?', '--help']:
|
||||||
print(_('''Usage:
|
print(_('''Usage:
|
||||||
diffuse [ [OPTION...] [FILE...] ]...
|
diffuse [ [OPTION...] [FILE...] ]...
|
||||||
diffuse ( -h | -? | --help | -v | --version )
|
diffuse ( -h | -? | --help | -v | --version )
|
||||||
|
@ -1683,7 +1680,7 @@ Display Options:
|
||||||
subdirs = ['diffuse']
|
subdirs = ['diffuse']
|
||||||
if data_dir is None:
|
if data_dir is None:
|
||||||
data_dir = os.path.expanduser('~')
|
data_dir = os.path.expanduser('~')
|
||||||
subdirs[:0] = [ '.local', 'share' ]
|
subdirs[:0] = ['.local', 'share']
|
||||||
data_dir = utils.make_subdirs(data_dir, subdirs)
|
data_dir = utils.make_subdirs(data_dir, subdirs)
|
||||||
|
|
||||||
# load resource files
|
# load resource files
|
||||||
|
@ -1739,58 +1736,58 @@ Display Options:
|
||||||
while i < argc:
|
while i < argc:
|
||||||
arg = args[i]
|
arg = args[i]
|
||||||
if len(arg) > 0 and arg[0] == '-':
|
if len(arg) > 0 and arg[0] == '-':
|
||||||
if i + 1 < argc and arg in [ '-c', '--commit' ]:
|
if i + 1 < argc and arg in ['-c', '--commit']:
|
||||||
# specified revision
|
# specified revision
|
||||||
funcs[mode](specs, labels, options)
|
funcs[mode](specs, labels, options)
|
||||||
i += 1
|
i += 1
|
||||||
rev = args[i]
|
rev = args[i]
|
||||||
specs, labels, options = [], [], { 'commit': args[i] }
|
specs, labels, options = [], [], { 'commit': args[i] }
|
||||||
mode = 'commit'
|
mode = 'commit'
|
||||||
elif arg in [ '-D', '--close-if-same' ]:
|
elif arg in ['-D', '--close-if-same']:
|
||||||
close_on_same = True
|
close_on_same = True
|
||||||
elif i + 1 < argc and arg in [ '-e', '--encoding' ]:
|
elif i + 1 < argc and arg in ['-e', '--encoding']:
|
||||||
i += 1
|
i += 1
|
||||||
encoding = args[i]
|
encoding = args[i]
|
||||||
encoding = encodings.aliases.aliases.get(encoding, encoding)
|
encoding = encodings.aliases.aliases.get(encoding, encoding)
|
||||||
elif arg in [ '-m', '--modified' ]:
|
elif arg in ['-m', '--modified']:
|
||||||
funcs[mode](specs, labels, options)
|
funcs[mode](specs, labels, options)
|
||||||
specs, labels, options = [], [], {}
|
specs, labels, options = [], [], {}
|
||||||
mode = 'modified'
|
mode = 'modified'
|
||||||
elif i + 1 < argc and arg in [ '-r', '--revision' ]:
|
elif i + 1 < argc and arg in ['-r', '--revision']:
|
||||||
# specified revision
|
# specified revision
|
||||||
i += 1
|
i += 1
|
||||||
revs.append((args[i], encoding))
|
revs.append((args[i], encoding))
|
||||||
elif arg in [ '-s', '--separate' ]:
|
elif arg in ['-s', '--separate']:
|
||||||
funcs[mode](specs, labels, options)
|
funcs[mode](specs, labels, options)
|
||||||
specs, labels, options = [], [], {}
|
specs, labels, options = [], [], {}
|
||||||
# open items in separate tabs
|
# open items in separate tabs
|
||||||
mode = 'separate'
|
mode = 'separate'
|
||||||
elif arg in [ '-t', '--tab' ]:
|
elif arg in ['-t', '--tab']:
|
||||||
funcs[mode](specs, labels, options)
|
funcs[mode](specs, labels, options)
|
||||||
specs, labels, options = [], [], {}
|
specs, labels, options = [], [], {}
|
||||||
# start a new tab
|
# start a new tab
|
||||||
mode = 'single'
|
mode = 'single'
|
||||||
elif i + 1 < argc and arg in [ '-V', '--vcs' ]:
|
elif i + 1 < argc and arg in ['-V', '--vcs']:
|
||||||
i += 1
|
i += 1
|
||||||
diff.prefs.setString('vcs_search_order', args[i])
|
diff.prefs.setString('vcs_search_order', args[i])
|
||||||
diff.preferences_updated()
|
diff.preferences_updated()
|
||||||
elif arg in [ '-b', '--ignore-space-change' ]:
|
elif arg in ['-b', '--ignore-space-change']:
|
||||||
diff.prefs.setBool('display_ignore_whitespace_changes', True)
|
diff.prefs.setBool('display_ignore_whitespace_changes', True)
|
||||||
diff.prefs.setBool('align_ignore_whitespace_changes', True)
|
diff.prefs.setBool('align_ignore_whitespace_changes', True)
|
||||||
diff.preferences_updated()
|
diff.preferences_updated()
|
||||||
elif arg in [ '-B', '--ignore-blank-lines' ]:
|
elif arg in ['-B', '--ignore-blank-lines']:
|
||||||
diff.prefs.setBool('display_ignore_blanklines', True)
|
diff.prefs.setBool('display_ignore_blanklines', True)
|
||||||
diff.prefs.setBool('align_ignore_blanklines', True)
|
diff.prefs.setBool('align_ignore_blanklines', True)
|
||||||
diff.preferences_updated()
|
diff.preferences_updated()
|
||||||
elif arg in [ '-E', '--ignore-end-of-line' ]:
|
elif arg in ['-E', '--ignore-end-of-line']:
|
||||||
diff.prefs.setBool('display_ignore_endofline', True)
|
diff.prefs.setBool('display_ignore_endofline', True)
|
||||||
diff.prefs.setBool('align_ignore_endofline', True)
|
diff.prefs.setBool('align_ignore_endofline', True)
|
||||||
diff.preferences_updated()
|
diff.preferences_updated()
|
||||||
elif arg in [ '-i', '--ignore-case' ]:
|
elif arg in ['-i', '--ignore-case']:
|
||||||
diff.prefs.setBool('display_ignore_case', True)
|
diff.prefs.setBool('display_ignore_case', True)
|
||||||
diff.prefs.setBool('align_ignore_case', True)
|
diff.prefs.setBool('align_ignore_case', True)
|
||||||
diff.preferences_updated()
|
diff.preferences_updated()
|
||||||
elif arg in [ '-w', '--ignore-all-space' ]:
|
elif arg in ['-w', '--ignore-all-space']:
|
||||||
diff.prefs.setBool('display_ignore_whitespace', True)
|
diff.prefs.setBool('display_ignore_whitespace', True)
|
||||||
diff.prefs.setBool('align_ignore_whitespace', True)
|
diff.prefs.setBool('align_ignore_whitespace', True)
|
||||||
diff.preferences_updated()
|
diff.preferences_updated()
|
||||||
|
@ -1828,8 +1825,8 @@ Display Options:
|
||||||
revs = []
|
revs = []
|
||||||
had_specs = True
|
had_specs = True
|
||||||
i += 1
|
i += 1
|
||||||
if mode in [ 'modified', 'commit' ] and len(specs) == 0:
|
if mode in ['modified', 'commit'] and len(specs) == 0:
|
||||||
specs.append((os.curdir, [ (None, encoding) ]))
|
specs.append((os.curdir, [(None, encoding)]))
|
||||||
had_specs = True
|
had_specs = True
|
||||||
funcs[mode](specs, labels, options)
|
funcs[mode](specs, labels, options)
|
||||||
|
|
||||||
|
|
|
@ -23,16 +23,13 @@ import os
|
||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
from diffuse import constants
|
||||||
|
from diffuse import utils
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk # noqa: E402
|
||||||
# pylint: enable=wrong-import-position
|
|
||||||
|
|
||||||
# pylint: disable-next=no-name-in-module
|
|
||||||
from diffuse import constants
|
|
||||||
|
|
||||||
from diffuse import utils
|
|
||||||
|
|
||||||
# class to store preferences and construct a dialogue for manipulating them
|
# class to store preferences and construct a dialogue for manipulating them
|
||||||
class Preferences:
|
class Preferences:
|
||||||
|
@ -52,7 +49,7 @@ class Preferences:
|
||||||
else:
|
else:
|
||||||
svk_bin = 'svk'
|
svk_bin = 'svk'
|
||||||
|
|
||||||
auto_detect_codecs = [ 'utf_8', 'utf_16', 'latin_1' ]
|
auto_detect_codecs = ['utf_8', 'utf_16', 'latin_1']
|
||||||
e = utils.norm_encoding(sys.getfilesystemencoding())
|
e = utils.norm_encoding(sys.getfilesystemencoding())
|
||||||
if e not in auto_detect_codecs:
|
if e not in auto_detect_codecs:
|
||||||
# insert after UTF-8 as the default encoding may prevent UTF-8 from
|
# insert after UTF-8 as the default encoding may prevent UTF-8 from
|
||||||
|
@ -75,50 +72,53 @@ class Preferences:
|
||||||
# [ 'String', name, default, label ]
|
# [ 'String', name, default, label ]
|
||||||
# [ 'File', name, default, label ]
|
# [ 'File', name, default, label ]
|
||||||
# [ 'Font', name, default, label ]
|
# [ 'Font', name, default, label ]
|
||||||
# pylint: disable=line-too-long
|
|
||||||
self.template = [
|
self.template = [
|
||||||
'FolderSet',
|
'FolderSet',
|
||||||
_('Display'),
|
_('Display'),
|
||||||
[ 'List',
|
[
|
||||||
[ 'Font', 'display_font', 'Monospace 10', _('Font') ],
|
'List',
|
||||||
[ 'Integer', 'display_tab_width', 8, _('Tab width'), 1, 1024 ],
|
['Font', 'display_font', 'Monospace 10', _('Font')],
|
||||||
[ 'Boolean', 'display_show_right_margin', True, _('Show right margin') ],
|
['Integer', 'display_tab_width', 8, _('Tab width'), 1, 1024],
|
||||||
[ 'Integer', 'display_right_margin', 80, _('Right margin'), 1, 8192 ],
|
['Boolean', 'display_show_right_margin', True, _('Show right margin')],
|
||||||
[ 'Boolean', 'display_show_line_numbers', True, _('Show line numbers') ],
|
['Integer', 'display_right_margin', 80, _('Right margin'), 1, 8192],
|
||||||
[ 'Boolean', 'display_show_whitespace', False, _('Show white space characters') ],
|
['Boolean', 'display_show_line_numbers', True, _('Show line numbers')],
|
||||||
[ 'Boolean', 'display_ignore_case', False, _('Ignore case differences') ],
|
['Boolean', 'display_show_whitespace', False, _('Show white space characters')],
|
||||||
[ 'Boolean', 'display_ignore_whitespace', False, _('Ignore white space differences') ],
|
['Boolean', 'display_ignore_case', False, _('Ignore case differences')],
|
||||||
[ 'Boolean', 'display_ignore_whitespace_changes', False, _('Ignore changes to white space') ],
|
['Boolean', 'display_ignore_whitespace', False, _('Ignore white space differences')], # noqa: E501
|
||||||
[ 'Boolean', 'display_ignore_blanklines', False, _('Ignore blank line differences') ],
|
['Boolean', 'display_ignore_whitespace_changes', False, _('Ignore changes to white space')], # noqa: E501
|
||||||
[ 'Boolean', 'display_ignore_endofline', False, _('Ignore end of line differences') ]
|
['Boolean', 'display_ignore_blanklines', False, _('Ignore blank line differences')],
|
||||||
|
['Boolean', 'display_ignore_endofline', False, _('Ignore end of line differences')]
|
||||||
],
|
],
|
||||||
_('Alignment'),
|
_('Alignment'),
|
||||||
[ 'List',
|
[
|
||||||
[ 'Boolean', 'align_ignore_case', False, _('Ignore case') ],
|
'List',
|
||||||
[ 'Boolean', 'align_ignore_whitespace', True, _('Ignore white space') ],
|
['Boolean', 'align_ignore_case', False, _('Ignore case')],
|
||||||
[ 'Boolean', 'align_ignore_whitespace_changes', False, _('Ignore changes to white space') ],
|
['Boolean', 'align_ignore_whitespace', True, _('Ignore white space')],
|
||||||
[ 'Boolean', 'align_ignore_blanklines', False, _('Ignore blank lines') ],
|
['Boolean', 'align_ignore_whitespace_changes', False, _('Ignore changes to white space')], # noqa: E501
|
||||||
[ 'Boolean', 'align_ignore_endofline', True, _('Ignore end of line characters') ]
|
['Boolean', 'align_ignore_blanklines', False, _('Ignore blank lines')],
|
||||||
|
['Boolean', 'align_ignore_endofline', True, _('Ignore end of line characters')]
|
||||||
],
|
],
|
||||||
_('Editor'),
|
_('Editor'),
|
||||||
[ 'List',
|
[
|
||||||
[ 'Boolean', 'editor_auto_indent', True, _('Auto indent') ],
|
'List',
|
||||||
[ 'Boolean', 'editor_expand_tabs', False, _('Expand tabs to spaces') ],
|
['Boolean', 'editor_auto_indent', True, _('Auto indent')],
|
||||||
[ 'Integer', 'editor_soft_tab_width', 8, _('Soft tab width'), 1, 1024 ]
|
['Boolean', 'editor_expand_tabs', False, _('Expand tabs to spaces')],
|
||||||
|
['Integer', 'editor_soft_tab_width', 8, _('Soft tab width'), 1, 1024]
|
||||||
],
|
],
|
||||||
_('Tabs'),
|
_('Tabs'),
|
||||||
[ 'List',
|
[
|
||||||
[ 'Integer', 'tabs_default_panes', 2, _('Default panes'), 2, 16 ],
|
'List',
|
||||||
[ 'Boolean', 'tabs_always_show', False, _('Always show the tab bar') ],
|
['Integer', 'tabs_default_panes', 2, _('Default panes'), 2, 16],
|
||||||
[ 'Boolean', 'tabs_warn_before_quit', True, _('Warn me when closing a tab will quit %s') % constants.APP_NAME ]
|
['Boolean', 'tabs_always_show', False, _('Always show the tab bar')],
|
||||||
|
['Boolean', 'tabs_warn_before_quit', True, _('Warn me when closing a tab will quit %s') % constants.APP_NAME] # noqa: E501
|
||||||
],
|
],
|
||||||
_('Regional Settings'),
|
_('Regional Settings'),
|
||||||
[ 'List',
|
[
|
||||||
[ 'Encoding', 'encoding_default_codec', sys.getfilesystemencoding(), _('Default codec') ],
|
'List',
|
||||||
[ 'String', 'encoding_auto_detect_codecs', ' '.join(auto_detect_codecs), _('Order of codecs used to identify encoding') ]
|
['Encoding', 'encoding_default_codec', sys.getfilesystemencoding(), _('Default codec')], # noqa: E501
|
||||||
|
['String', 'encoding_auto_detect_codecs', ' '.join(auto_detect_codecs), _('Order of codecs used to identify encoding')] # noqa: E501
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
# pylint: disable=line-too-long
|
|
||||||
|
|
||||||
# conditions used to determine if a preference should be greyed out
|
# conditions used to determine if a preference should be greyed out
|
||||||
self.disable_when = {
|
self.disable_when = {
|
||||||
|
@ -138,22 +138,21 @@ class Preferences:
|
||||||
root += '\\'
|
root += '\\'
|
||||||
self.template.extend([
|
self.template.extend([
|
||||||
_('Cygwin'),
|
_('Cygwin'),
|
||||||
[ 'List',
|
['List',
|
||||||
[ 'File', 'cygwin_root', os.path.join(root, 'cygwin'), _('Root directory') ],
|
['File', 'cygwin_root', os.path.join(root, 'cygwin'), _('Root directory')],
|
||||||
[ 'String', 'cygwin_cygdrive_prefix', '/cygdrive', _('Cygdrive prefix') ]
|
['String', 'cygwin_cygdrive_prefix', '/cygdrive', _('Cygdrive prefix')]]
|
||||||
]
|
|
||||||
])
|
])
|
||||||
|
|
||||||
# create template for Version Control options
|
# create template for Version Control options
|
||||||
vcs = [ ('bzr', 'Bazaar', 'bzr'),
|
vcs = [('bzr', 'Bazaar', 'bzr'),
|
||||||
('cvs', 'CVS', 'cvs'),
|
('cvs', 'CVS', 'cvs'),
|
||||||
('darcs', 'Darcs', 'darcs'),
|
('darcs', 'Darcs', 'darcs'),
|
||||||
('git', 'Git', 'git'),
|
('git', 'Git', 'git'),
|
||||||
('hg', 'Mercurial', 'hg'),
|
('hg', 'Mercurial', 'hg'),
|
||||||
('mtn', 'Monotone', 'mtn'),
|
('mtn', 'Monotone', 'mtn'),
|
||||||
('rcs', 'RCS', None),
|
('rcs', 'RCS', None),
|
||||||
('svn', 'Subversion', 'svn'),
|
('svn', 'Subversion', 'svn'),
|
||||||
('svk', 'SVK', svk_bin) ]
|
('svk', 'SVK', svk_bin)]
|
||||||
|
|
||||||
vcs_template = [
|
vcs_template = [
|
||||||
'List', [
|
'List', [
|
||||||
|
@ -163,15 +162,15 @@ class Preferences:
|
||||||
_('Version control system search order')
|
_('Version control system search order')
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
vcs_folders_template = [ 'FolderSet' ]
|
vcs_folders_template = ['FolderSet']
|
||||||
for key, name, cmd in vcs:
|
for key, name, cmd in vcs:
|
||||||
temp = [ 'List' ]
|
temp = ['List']
|
||||||
if key == 'rcs':
|
if key == 'rcs':
|
||||||
# RCS uses multiple commands
|
# RCS uses multiple commands
|
||||||
temp.extend([ [ 'File', key + '_bin_co', 'co', _('"co" command') ],
|
temp.extend([['File', key + '_bin_co', 'co', _('"co" command')],
|
||||||
[ 'File', key + '_bin_rlog', 'rlog', _('"rlog" command') ] ])
|
['File', key + '_bin_rlog', 'rlog', _('"rlog" command')]])
|
||||||
else:
|
else:
|
||||||
temp.extend([ [ 'File', key + '_bin', cmd, _('Command') ] ])
|
temp.extend([['File', key + '_bin', cmd, _('Command')]])
|
||||||
if utils.isWindows():
|
if utils.isWindows():
|
||||||
temp.append([
|
temp.append([
|
||||||
'Boolean',
|
'Boolean',
|
||||||
|
@ -186,10 +185,10 @@ class Preferences:
|
||||||
False,
|
False,
|
||||||
_('Update paths for Cygwin')
|
_('Update paths for Cygwin')
|
||||||
])
|
])
|
||||||
vcs_folders_template.extend([ name, temp ])
|
vcs_folders_template.extend([name, temp])
|
||||||
vcs_template.append(vcs_folders_template)
|
vcs_template.append(vcs_folders_template)
|
||||||
|
|
||||||
self.template.extend([ _('Version Control'), vcs_template ])
|
self.template.extend([_('Version Control'), vcs_template])
|
||||||
self._initFromTemplate(self.template)
|
self._initFromTemplate(self.template)
|
||||||
self.default_bool_prefs = self.bool_prefs.copy()
|
self.default_bool_prefs = self.bool_prefs.copy()
|
||||||
self.default_int_prefs = self.int_prefs.copy()
|
self.default_int_prefs = self.int_prefs.copy()
|
||||||
|
@ -208,7 +207,9 @@ class Preferences:
|
||||||
if len(a) == 2 and p in self.bool_prefs:
|
if len(a) == 2 and p in self.bool_prefs:
|
||||||
self.bool_prefs[p] = (a[1] == 'True')
|
self.bool_prefs[p] = (a[1] == 'True')
|
||||||
elif len(a) == 2 and p in self.int_prefs:
|
elif len(a) == 2 and p in self.int_prefs:
|
||||||
self.int_prefs[p] = max(self.int_prefs_min[p], min(int(a[1]), self.int_prefs_max[p]))
|
self.int_prefs[p] = max(
|
||||||
|
self.int_prefs_min[p],
|
||||||
|
min(int(a[1]), self.int_prefs_max[p]))
|
||||||
elif len(a) == 2 and p in self.string_prefs:
|
elif len(a) == 2 and p in self.string_prefs:
|
||||||
self.string_prefs[p] = a[1]
|
self.string_prefs[p] = a[1]
|
||||||
else:
|
else:
|
||||||
|
@ -238,7 +239,7 @@ class Preferences:
|
||||||
self.int_prefs[template[1]] = template[2]
|
self.int_prefs[template[1]] = template[2]
|
||||||
self.int_prefs_min[template[1]] = template[4]
|
self.int_prefs_min[template[1]] = template[4]
|
||||||
self.int_prefs_max[template[1]] = template[5]
|
self.int_prefs_max[template[1]] = template[5]
|
||||||
elif template[0] in [ 'String', 'File', 'Font', 'Encoding' ]:
|
elif template[0] in ['String', 'File', 'Font', 'Encoding']:
|
||||||
self.string_prefs[template[1]] = template[2]
|
self.string_prefs[template[1]] = template[2]
|
||||||
|
|
||||||
# callback used when a preference is toggled
|
# callback used when a preference is toggled
|
||||||
|
@ -263,10 +264,10 @@ class Preferences:
|
||||||
p, t = v
|
p, t = v
|
||||||
if widgets[p].get_active() == t:
|
if widgets[p].get_active() == t:
|
||||||
widgets[k].set_sensitive(False)
|
widgets[k].set_sensitive(False)
|
||||||
dialog.vbox.add(w) # pylint: disable=no-member
|
dialog.vbox.add(w)
|
||||||
w.show()
|
w.show()
|
||||||
|
|
||||||
accept = (dialog.run() == Gtk.ResponseType.OK) # pylint: disable=no-member
|
accept = (dialog.run() == Gtk.ResponseType.OK)
|
||||||
if accept:
|
if accept:
|
||||||
for k in self.bool_prefs:
|
for k in self.bool_prefs:
|
||||||
self.bool_prefs[k] = widgets[k].get_active()
|
self.bool_prefs[k] = widgets[k].get_active()
|
||||||
|
@ -288,8 +289,7 @@ class Preferences:
|
||||||
ss.append(f'{k} "{v_escaped}"\n')
|
ss.append(f'{k} "{v_escaped}"\n')
|
||||||
ss.sort()
|
ss.sort()
|
||||||
with open(self.path, 'w', encoding='utf-8') as f:
|
with open(self.path, 'w', encoding='utf-8') as f:
|
||||||
# pylint: disable-next=line-too-long
|
f.write(f'# This prefs file was generated by {constants.APP_NAME} {constants.VERSION}.\n\n') # noqa: E501
|
||||||
f.write(f'# This prefs file was generated by {constants.APP_NAME} {constants.VERSION}.\n\n')
|
|
||||||
for s in ss:
|
for s in ss:
|
||||||
f.write(s)
|
f.write(s)
|
||||||
except IOError:
|
except IOError:
|
||||||
|
@ -337,7 +337,7 @@ class Preferences:
|
||||||
label.set_yalign(0.5)
|
label.set_yalign(0.5)
|
||||||
table.attach(label, 0, i, 1, 1)
|
table.attach(label, 0, i, 1, 1)
|
||||||
label.show()
|
label.show()
|
||||||
if tpl[0] in [ 'Font', 'Integer' ]:
|
if tpl[0] in ['Font', 'Integer']:
|
||||||
entry = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
entry = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||||
if tpl[0] == 'Font':
|
if tpl[0] == 'Font':
|
||||||
button = _FontButton()
|
button = _FontButton()
|
||||||
|
@ -393,12 +393,12 @@ class Preferences:
|
||||||
# attempt to convert a string to unicode from an unknown encoding
|
# attempt to convert a string to unicode from an unknown encoding
|
||||||
def convertToUnicode(self, s):
|
def convertToUnicode(self, s):
|
||||||
# a BOM is required for autodetecting UTF16 and UTF32
|
# a BOM is required for autodetecting UTF16 and UTF32
|
||||||
magic = { 'utf16': [ codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE ],
|
magic = {'utf16': [codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE],
|
||||||
'utf32': [ codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE ] }
|
'utf32': [codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE]}
|
||||||
for encoding in self._getDefaultEncodings():
|
for encoding in self._getDefaultEncodings():
|
||||||
try:
|
try:
|
||||||
encoding = encoding.lower().replace('-', '').replace('_', '')
|
encoding = encoding.lower().replace('-', '').replace('_', '')
|
||||||
for m in magic.get(encoding, [ b'' ]):
|
for m in magic.get(encoding, [b'']):
|
||||||
if s.startswith(m):
|
if s.startswith(m):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -406,7 +406,7 @@ class Preferences:
|
||||||
return str(s, encoding=encoding), encoding
|
return str(s, encoding=encoding), encoding
|
||||||
except (UnicodeDecodeError, LookupError):
|
except (UnicodeDecodeError, LookupError):
|
||||||
pass
|
pass
|
||||||
return ''.join([ chr(ord(c)) for c in s ]), None
|
return ''.join([chr(ord(c)) for c in s]), None
|
||||||
|
|
||||||
# cygwin and native applications can be used on windows, use this method
|
# cygwin and native applications can be used on windows, use this method
|
||||||
# to convert a path to the usual form expected on sys.platform
|
# to convert a path to the usual form expected on sys.platform
|
||||||
|
@ -415,37 +415,37 @@ class Preferences:
|
||||||
# treat as a cygwin path
|
# treat as a cygwin path
|
||||||
s = s.replace(os.sep, '/')
|
s = s.replace(os.sep, '/')
|
||||||
# convert to a Windows native style path
|
# convert to a Windows native style path
|
||||||
p = [ a for a in s.split('/') if a != '' ]
|
p = [a for a in s.split('/') if a != '']
|
||||||
if s.startswith('//'):
|
if s.startswith('//'):
|
||||||
p[:0] = [ '', '' ]
|
p[:0] = ['', '']
|
||||||
elif s.startswith('/'):
|
elif s.startswith('/'):
|
||||||
pr = [ a for a in self.getString('cygwin_cygdrive_prefix').split('/') if a != '' ]
|
pr = [a for a in self.getString('cygwin_cygdrive_prefix').split('/') if a != '']
|
||||||
n = len(pr)
|
n = len(pr)
|
||||||
if len(p) > n and len(p[n]) == 1 and p[:n] == pr:
|
if len(p) > n and len(p[n]) == 1 and p[:n] == pr:
|
||||||
# path starts with cygdrive prefix
|
# path starts with cygdrive prefix
|
||||||
p[:n + 1] = [ p[n] + ':' ]
|
p[:n + 1] = [p[n] + ':']
|
||||||
else:
|
else:
|
||||||
# full path
|
# full path
|
||||||
p[:0] = [ a for a in self.getString('cygwin_root').split(os.sep) if a != '' ]
|
p[:0] = [a for a in self.getString('cygwin_root').split(os.sep) if a != '']
|
||||||
# add trailing slash
|
# add trailing slash
|
||||||
if p[-1] != '' and s.endswith('/'):
|
if p[-1] != '' and s.endswith('/'):
|
||||||
p.append('')
|
p.append('')
|
||||||
s = os.sep.join(p)
|
s = os.sep.join(p)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
# adaptor class to allow a Gtk.FontButton to be read like a Gtk.Entry
|
# adaptor class to allow a Gtk.FontButton to be read like a Gtk.Entry
|
||||||
class _FontButton(Gtk.FontButton):
|
class _FontButton(Gtk.FontButton):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Gtk.FontButton.__init__(self)
|
Gtk.FontButton.__init__(self)
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
# pylint: disable=no-member
|
|
||||||
return self.get_font_name()
|
return self.get_font_name()
|
||||||
|
|
||||||
|
|
||||||
# text entry widget with a button to help pick file names
|
# text entry widget with a button to help pick file names
|
||||||
class _FileEntry(Gtk.Box):
|
class _FileEntry(Gtk.Box):
|
||||||
def __init__(self, parent, title):
|
def __init__(self, parent, title):
|
||||||
# pylint: disable=no-member
|
|
||||||
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
|
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
|
||||||
self.toplevel = parent
|
self.toplevel = parent
|
||||||
self.title = title
|
self.title = title
|
||||||
|
@ -463,7 +463,6 @@ class _FileEntry(Gtk.Box):
|
||||||
|
|
||||||
# action performed when the pick file button is pressed
|
# action performed when the pick file button is pressed
|
||||||
def chooseFile(self, widget):
|
def chooseFile(self, widget):
|
||||||
# pylint: disable=no-member
|
|
||||||
dialog = Gtk.FileChooserDialog(
|
dialog = Gtk.FileChooserDialog(
|
||||||
self.title,
|
self.title,
|
||||||
self.toplevel,
|
self.toplevel,
|
||||||
|
|
|
@ -29,13 +29,12 @@ import os
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
from diffuse import utils
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gdk', '3.0')
|
gi.require_version('Gdk', '3.0')
|
||||||
from gi.repository import Gdk
|
from gi.repository import Gdk # noqa: E402
|
||||||
# pylint: enable=wrong-import-position
|
|
||||||
|
|
||||||
from diffuse import utils
|
|
||||||
|
|
||||||
class Resources:
|
class Resources:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -142,8 +141,8 @@ class Resources:
|
||||||
set_binding('line_mode', 'next_difference', 'n')
|
set_binding('line_mode', 'next_difference', 'n')
|
||||||
set_binding('line_mode', 'last_difference', 'Ctrl+End')
|
set_binding('line_mode', 'last_difference', 'Ctrl+End')
|
||||||
set_binding('line_mode', 'last_difference', 'Shift+N')
|
set_binding('line_mode', 'last_difference', 'Shift+N')
|
||||||
#set_binding('line_mode', 'copy_selection_right', 'Shift+L')
|
# set_binding('line_mode', 'copy_selection_right', 'Shift+L')
|
||||||
#set_binding('line_mode', 'copy_selection_left', 'Shift+H')
|
# set_binding('line_mode', 'copy_selection_left', 'Shift+H')
|
||||||
set_binding('line_mode', 'copy_left_into_selection', 'Shift+L')
|
set_binding('line_mode', 'copy_left_into_selection', 'Shift+L')
|
||||||
set_binding('line_mode', 'copy_right_into_selection', 'Shift+H')
|
set_binding('line_mode', 'copy_right_into_selection', 'Shift+H')
|
||||||
set_binding('line_mode', 'merge_from_left_then_right', 'm')
|
set_binding('line_mode', 'merge_from_left_then_right', 'm')
|
||||||
|
@ -170,31 +169,33 @@ class Resources:
|
||||||
|
|
||||||
# default colours
|
# default colours
|
||||||
self.colours = {
|
self.colours = {
|
||||||
'alignment' : _Colour(1.0, 1.0, 0.0),
|
'alignment': _Colour(1.0, 1.0, 0.0),
|
||||||
'character_selection' : _Colour(0.7, 0.7, 1.0),
|
'character_selection': _Colour(0.7, 0.7, 1.0),
|
||||||
'cursor' : _Colour(0.0, 0.0, 0.0),
|
'cursor': _Colour(0.0, 0.0, 0.0),
|
||||||
'difference_1' : _Colour(1.0, 0.625, 0.625),
|
'difference_1': _Colour(1.0, 0.625, 0.625),
|
||||||
'difference_2' : _Colour(0.85, 0.625, 0.775),
|
'difference_2': _Colour(0.85, 0.625, 0.775),
|
||||||
'difference_3' : _Colour(0.85, 0.775, 0.625),
|
'difference_3': _Colour(0.85, 0.775, 0.625),
|
||||||
'hatch' : _Colour(0.8, 0.8, 0.8),
|
'hatch': _Colour(0.8, 0.8, 0.8),
|
||||||
'line_number' : _Colour(0.0, 0.0, 0.0),
|
'line_number': _Colour(0.0, 0.0, 0.0),
|
||||||
'line_number_background' : _Colour(0.75, 0.75, 0.75),
|
'line_number_background': _Colour(0.75, 0.75, 0.75),
|
||||||
'line_selection' : _Colour(0.7, 0.7, 1.0),
|
'line_selection': _Colour(0.7, 0.7, 1.0),
|
||||||
'map_background' : _Colour(0.6, 0.6, 0.6),
|
'map_background': _Colour(0.6, 0.6, 0.6),
|
||||||
'margin' : _Colour(0.8, 0.8, 0.8),
|
'margin': _Colour(0.8, 0.8, 0.8),
|
||||||
'edited' : _Colour(0.5, 1.0, 0.5),
|
'edited': _Colour(0.5, 1.0, 0.5),
|
||||||
'preedit' : _Colour(0.0, 0.0, 0.0),
|
'preedit': _Colour(0.0, 0.0, 0.0),
|
||||||
'text' : _Colour(0.0, 0.0, 0.0),
|
'text': _Colour(0.0, 0.0, 0.0),
|
||||||
'text_background' : _Colour(1.0, 1.0, 1.0) }
|
'text_background': _Colour(1.0, 1.0, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
# default floats
|
# default floats
|
||||||
self.floats = {
|
self.floats = {
|
||||||
'alignment_opacity' : 1.0,
|
'alignment_opacity': 1.0,
|
||||||
'character_difference_opacity' : 0.4,
|
'character_difference_opacity': 0.4,
|
||||||
'character_selection_opacity' : 0.4,
|
'character_selection_opacity': 0.4,
|
||||||
'edited_opacity' : 0.4,
|
'edited_opacity': 0.4,
|
||||||
'line_difference_opacity' : 0.3,
|
'line_difference_opacity': 0.3,
|
||||||
'line_selection_opacity' : 0.4 }
|
'line_selection_opacity': 0.4
|
||||||
|
}
|
||||||
|
|
||||||
# default strings
|
# default strings
|
||||||
self.strings = {}
|
self.strings = {}
|
||||||
|
@ -222,7 +223,7 @@ class Resources:
|
||||||
elif token == 'Ctrl':
|
elif token == 'Ctrl':
|
||||||
modifiers |= Gdk.ModifierType.CONTROL_MASK
|
modifiers |= Gdk.ModifierType.CONTROL_MASK
|
||||||
elif token == 'Alt':
|
elif token == 'Alt':
|
||||||
modifiers |= Gdk.ModifierType.MOD1_MASK # pylint: disable=no-member
|
modifiers |= Gdk.ModifierType.MOD1_MASK
|
||||||
elif len(token) == 0 or token[0] == '_':
|
elif len(token) == 0 or token[0] == '_':
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
else:
|
else:
|
||||||
|
@ -265,7 +266,7 @@ class Resources:
|
||||||
|
|
||||||
def getKeyBindings(self, ctx, s):
|
def getKeyBindings(self, ctx, s):
|
||||||
try:
|
try:
|
||||||
return [ t for c, t in self.keybindings[(ctx, s)].keys() ]
|
return [t for c, t in self.keybindings[(ctx, s)].keys()]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@ -351,7 +352,7 @@ class Resources:
|
||||||
path = os.path.join(utils.globEscape(os.path.dirname(file_name)), path)
|
path = os.path.join(utils.globEscape(os.path.dirname(file_name)), path)
|
||||||
paths = glob.glob(path)
|
paths = glob.glob(path)
|
||||||
if len(paths) == 0:
|
if len(paths) == 0:
|
||||||
paths = [ path ]
|
paths = [path]
|
||||||
for path in paths:
|
for path in paths:
|
||||||
# convert to absolute path so the location of
|
# convert to absolute path so the location of
|
||||||
# any processing errors are reported with
|
# any processing errors are reported with
|
||||||
|
@ -363,7 +364,7 @@ class Resources:
|
||||||
self.setKeyBinding(args[1], args[2], args[3])
|
self.setKeyBinding(args[1], args[2], args[3])
|
||||||
# eg. set the regular background colour to white
|
# eg. set the regular background colour to white
|
||||||
# colour text_background 1.0 1.0 1.0
|
# colour text_background 1.0 1.0 1.0
|
||||||
elif args[0] in [ 'colour', 'color' ] and len(args) == 5:
|
elif args[0] in ['colour', 'color'] and len(args) == 5:
|
||||||
self.colours[args[1]] = _Colour(float(args[2]), float(args[3]), float(args[4]))
|
self.colours[args[1]] = _Colour(float(args[2]), float(args[3]), float(args[4]))
|
||||||
# eg. set opacity of the line_selection colour
|
# eg. set opacity of the line_selection colour
|
||||||
# float line_selection_opacity 0.4
|
# float line_selection_opacity 0.4
|
||||||
|
@ -459,11 +460,11 @@ class Resources:
|
||||||
self.syntax_magic_patterns[key] = re.compile(args[2], flags)
|
self.syntax_magic_patterns[key] = re.compile(args[2], flags)
|
||||||
else:
|
else:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
# pylint: disable-next=bare-except
|
# except ValueError:
|
||||||
except: # Grr... the 're' module throws weird errors
|
except: # noqa: E722 # Grr... the 're' module throws weird errors
|
||||||
#except ValueError:
|
|
||||||
utils.logError(_(f'Error processing line {i + 1} of {file_name}.'))
|
utils.logError(_(f'Error processing line {i + 1} of {file_name}.'))
|
||||||
|
|
||||||
|
|
||||||
# colour resources
|
# colour resources
|
||||||
class _Colour:
|
class _Colour:
|
||||||
def __init__(self, r, g, b, a=1.0):
|
def __init__(self, r, g, b, a=1.0):
|
||||||
|
@ -489,6 +490,7 @@ class _Colour:
|
||||||
def over(self, other):
|
def over(self, other):
|
||||||
return self + other * (1 - self.alpha)
|
return self + other * (1 - self.alpha)
|
||||||
|
|
||||||
|
|
||||||
# class to build and run a finite state machine for identifying syntax tokens
|
# class to build and run a finite state machine for identifying syntax tokens
|
||||||
class _SyntaxParser:
|
class _SyntaxParser:
|
||||||
# create a new state machine that begins in initial_state and classifies
|
# create a new state machine that begins in initial_state and classifies
|
||||||
|
@ -502,7 +504,7 @@ class _SyntaxParser:
|
||||||
# mappings from a state to a list of (pattern, token_type, next_state)
|
# mappings from a state to a list of (pattern, token_type, next_state)
|
||||||
# tuples indicating the new state for the state machine when 'pattern'
|
# tuples indicating the new state for the state machine when 'pattern'
|
||||||
# is matched and how to classify the matched characters
|
# is matched and how to classify the matched characters
|
||||||
self.transitions_lookup = { initial_state : [] }
|
self.transitions_lookup = {initial_state: []}
|
||||||
|
|
||||||
# Adds a new edge to the finite state machine from prev_state to
|
# Adds a new edge to the finite state machine from prev_state to
|
||||||
# next_state. Characters will be identified as token_type when pattern is
|
# next_state. Characters will be identified as token_type when pattern is
|
||||||
|
@ -536,4 +538,5 @@ class _SyntaxParser:
|
||||||
start = end
|
start = end
|
||||||
return state_name, blocks
|
return state_name, blocks
|
||||||
|
|
||||||
|
|
||||||
theResources = Resources()
|
theResources = Resources()
|
||||||
|
|
|
@ -23,14 +23,12 @@ import locale
|
||||||
import subprocess
|
import subprocess
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
from diffuse import constants
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk # noqa: E402
|
||||||
# pylint: enable=wrong-import-position
|
|
||||||
|
|
||||||
# pylint: disable-next=no-name-in-module
|
|
||||||
from diffuse import constants
|
|
||||||
|
|
||||||
# convenience class for displaying a message dialogue
|
# convenience class for displaying a message dialogue
|
||||||
class MessageDialog(Gtk.MessageDialog):
|
class MessageDialog(Gtk.MessageDialog):
|
||||||
|
@ -48,6 +46,7 @@ class MessageDialog(Gtk.MessageDialog):
|
||||||
text=s)
|
text=s)
|
||||||
self.set_title(constants.APP_NAME)
|
self.set_title(constants.APP_NAME)
|
||||||
|
|
||||||
|
|
||||||
# widget to help pick an encoding
|
# widget to help pick an encoding
|
||||||
class EncodingMenu(Gtk.Box):
|
class EncodingMenu(Gtk.Box):
|
||||||
def __init__(self, prefs, autodetect=False):
|
def __init__(self, prefs, autodetect=False):
|
||||||
|
@ -59,7 +58,7 @@ class EncodingMenu(Gtk.Box):
|
||||||
if autodetect:
|
if autodetect:
|
||||||
self.encodings.insert(0, None)
|
self.encodings.insert(0, None)
|
||||||
combobox.prepend_text(_('Auto Detect'))
|
combobox.prepend_text(_('Auto Detect'))
|
||||||
self.pack_start(combobox, False, False, 0) # pylint: disable=no-member
|
self.pack_start(combobox, False, False, 0)
|
||||||
combobox.show()
|
combobox.show()
|
||||||
|
|
||||||
def set_text(self, encoding):
|
def set_text(self, encoding):
|
||||||
|
@ -71,31 +70,37 @@ class EncodingMenu(Gtk.Box):
|
||||||
i = self.combobox.get_active()
|
i = self.combobox.get_active()
|
||||||
return self.encodings[i] if i >= 0 else None
|
return self.encodings[i] if i >= 0 else None
|
||||||
|
|
||||||
|
|
||||||
# platform test
|
# platform test
|
||||||
def isWindows():
|
def isWindows():
|
||||||
return os.name == 'nt'
|
return os.name == 'nt'
|
||||||
|
|
||||||
|
|
||||||
def _logPrintOutput(msg):
|
def _logPrintOutput(msg):
|
||||||
if constants.log_print_output:
|
if constants.log_print_output:
|
||||||
print(msg, file=sys.stderr)
|
print(msg, file=sys.stderr)
|
||||||
if constants.log_print_stack:
|
if constants.log_print_stack:
|
||||||
traceback.print_stack()
|
traceback.print_stack()
|
||||||
|
|
||||||
|
|
||||||
# convenience function to display debug messages
|
# convenience function to display debug messages
|
||||||
def logDebug(msg):
|
def logDebug(msg):
|
||||||
_logPrintOutput(f'DEBUG: {msg}')
|
_logPrintOutput(f'DEBUG: {msg}')
|
||||||
|
|
||||||
|
|
||||||
# report error messages
|
# report error messages
|
||||||
def logError(msg):
|
def logError(msg):
|
||||||
_logPrintOutput(f'ERROR: {msg}')
|
_logPrintOutput(f'ERROR: {msg}')
|
||||||
|
|
||||||
|
|
||||||
# report error messages and show dialog
|
# report error messages and show dialog
|
||||||
def logErrorAndDialog(msg,parent=None):
|
def logErrorAndDialog(msg, parent=None):
|
||||||
logError(msg)
|
logError(msg)
|
||||||
dialog = MessageDialog(parent, Gtk.MessageType.ERROR, msg)
|
dialog = MessageDialog(parent, Gtk.MessageType.ERROR, msg)
|
||||||
dialog.run() # pylint: disable=no-member
|
dialog.run()
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
|
|
||||||
|
|
||||||
# create nested subdirectories and return the complete path
|
# create nested subdirectories and return the complete path
|
||||||
def make_subdirs(p, ss):
|
def make_subdirs(p, ss):
|
||||||
for s in ss:
|
for s in ss:
|
||||||
|
@ -107,6 +112,7 @@ def make_subdirs(p, ss):
|
||||||
pass
|
pass
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
|
||||||
# returns the Windows drive or share from a from an absolute path
|
# returns the Windows drive or share from a from an absolute path
|
||||||
def _drive_from_path(path):
|
def _drive_from_path(path):
|
||||||
d = path.split(os.sep)
|
d = path.split(os.sep)
|
||||||
|
@ -114,20 +120,22 @@ def _drive_from_path(path):
|
||||||
return os.path.join(d[:4])
|
return os.path.join(d[:4])
|
||||||
return d[0]
|
return d[0]
|
||||||
|
|
||||||
|
|
||||||
# constructs a relative path from 'a' to 'b', both should be absolute paths
|
# constructs a relative path from 'a' to 'b', both should be absolute paths
|
||||||
def relpath(a, b):
|
def relpath(a, b):
|
||||||
if isWindows():
|
if isWindows():
|
||||||
if _drive_from_path(a) != _drive_from_path(b):
|
if _drive_from_path(a) != _drive_from_path(b):
|
||||||
return b
|
return b
|
||||||
c1 = [ c for c in a.split(os.sep) if c != '' ]
|
c1 = [c for c in a.split(os.sep) if c != '']
|
||||||
c2 = [ c for c in b.split(os.sep) if c != '' ]
|
c2 = [c for c in b.split(os.sep) if c != '']
|
||||||
i, n = 0, len(c1)
|
i, n = 0, len(c1)
|
||||||
while i < n and i < len(c2) and c1[i] == c2[i]:
|
while i < n and i < len(c2) and c1[i] == c2[i]:
|
||||||
i += 1
|
i += 1
|
||||||
r = (n - i) * [ os.pardir ]
|
r = (n - i) * [os.pardir]
|
||||||
r.extend(c2[i:])
|
r.extend(c2[i:])
|
||||||
return os.sep.join(r)
|
return os.sep.join(r)
|
||||||
|
|
||||||
|
|
||||||
# helper function prevent files from being confused with command line options
|
# helper function prevent files from being confused with command line options
|
||||||
# by prepending './' to the basename
|
# by prepending './' to the basename
|
||||||
def safeRelativePath(abspath1, name, prefs, cygwin_pref):
|
def safeRelativePath(abspath1, name, prefs, cygwin_pref):
|
||||||
|
@ -139,24 +147,28 @@ def safeRelativePath(abspath1, name, prefs, cygwin_pref):
|
||||||
s = s.replace('/', '\\')
|
s = s.replace('/', '\\')
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
# escape arguments for use with bash
|
# escape arguments for use with bash
|
||||||
def _bash_escape(s):
|
def _bash_escape(s):
|
||||||
return "'" + s.replace("'", "'\\''") + "'"
|
return "'" + s.replace("'", "'\\''") + "'"
|
||||||
|
|
||||||
|
|
||||||
def _use_flatpak():
|
def _use_flatpak():
|
||||||
return constants.use_flatpak
|
return constants.use_flatpak
|
||||||
|
|
||||||
|
|
||||||
# use popen to read the output of a command
|
# use popen to read the output of a command
|
||||||
def popenRead(dn, cmd, prefs, bash_pref, success_results=None):
|
def popenRead(dn, cmd, prefs, bash_pref, success_results=None):
|
||||||
if success_results is None:
|
if success_results is None:
|
||||||
success_results = [ 0 ]
|
success_results = [0]
|
||||||
if isWindows() and prefs.getBool(bash_pref):
|
if isWindows() and prefs.getBool(bash_pref):
|
||||||
# launch the command from a bash shell is requested
|
# launch the command from a bash shell is requested
|
||||||
cmd = [
|
cmd = [
|
||||||
prefs.convertToNativePath('/bin/bash.exe'),
|
prefs.convertToNativePath('/bin/bash.exe'),
|
||||||
'-l',
|
'-l',
|
||||||
'-c',
|
'-c',
|
||||||
f"cd {_bash_escape(dn)}; {' '.join([ _bash_escape(arg) for arg in cmd ])}" ]
|
f"cd {_bash_escape(dn)}; {' '.join([ _bash_escape(arg) for arg in cmd ])}"
|
||||||
|
]
|
||||||
dn = None
|
dn = None
|
||||||
# use subprocess.Popen to retrieve the file contents
|
# use subprocess.Popen to retrieve the file contents
|
||||||
if isWindows():
|
if isWindows():
|
||||||
|
@ -166,9 +178,8 @@ def popenRead(dn, cmd, prefs, bash_pref, success_results=None):
|
||||||
else:
|
else:
|
||||||
info = None
|
info = None
|
||||||
if _use_flatpak():
|
if _use_flatpak():
|
||||||
cmd = [ 'flatpak-spawn', '--host' ] + cmd
|
cmd = ['flatpak-spawn', '--host'] + cmd
|
||||||
with (
|
with (subprocess.Popen(
|
||||||
subprocess.Popen(
|
|
||||||
cmd,
|
cmd,
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
|
@ -186,6 +197,7 @@ def popenRead(dn, cmd, prefs, bash_pref, success_results=None):
|
||||||
raise IOError('Command failed.')
|
raise IOError('Command failed.')
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
# returns the number of characters in the string excluding any line ending
|
# returns the number of characters in the string excluding any line ending
|
||||||
# characters
|
# characters
|
||||||
def len_minus_line_ending(s):
|
def len_minus_line_ending(s):
|
||||||
|
@ -198,28 +210,34 @@ def len_minus_line_ending(s):
|
||||||
n -= 1
|
n -= 1
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
# returns the string without the line ending characters
|
# returns the string without the line ending characters
|
||||||
def strip_eol(s):
|
def strip_eol(s):
|
||||||
if s:
|
if s:
|
||||||
s = s[:len_minus_line_ending(s)]
|
s = s[:len_minus_line_ending(s)]
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
# returns the list of strings without line ending characters
|
# returns the list of strings without line ending characters
|
||||||
def _strip_eols(ss):
|
def _strip_eols(ss):
|
||||||
return [ strip_eol(s) for s in ss ]
|
return [strip_eol(s) for s in ss]
|
||||||
|
|
||||||
|
|
||||||
# use popen to read the output of a command
|
# use popen to read the output of a command
|
||||||
def popenReadLines(dn, cmd, prefs, bash_pref, success_results=None):
|
def popenReadLines(dn, cmd, prefs, bash_pref, success_results=None):
|
||||||
return _strip_eols(splitlines(popenRead(
|
return _strip_eols(splitlines(popenRead(
|
||||||
dn, cmd, prefs, bash_pref, success_results).decode('utf-8', errors='ignore')))
|
dn, cmd, prefs, bash_pref, success_results).decode('utf-8', errors='ignore')))
|
||||||
|
|
||||||
|
|
||||||
def readconfiglines(fd):
|
def readconfiglines(fd):
|
||||||
return fd.read().replace('\r', '').split('\n')
|
return fd.read().replace('\r', '').split('\n')
|
||||||
|
|
||||||
|
|
||||||
# escape special glob characters
|
# escape special glob characters
|
||||||
def globEscape(s):
|
def globEscape(s):
|
||||||
m = { c: f'[{c}]' for c in '[]?*' }
|
m = {c: f'[{c}]' for c in '[]?*'}
|
||||||
return ''.join([ m.get(c, c) for c in s ])
|
return ''.join([m.get(c, c) for c in s])
|
||||||
|
|
||||||
|
|
||||||
# split string into lines based upon DOS, Mac, and Unix line endings
|
# split string into lines based upon DOS, Mac, and Unix line endings
|
||||||
def splitlines(text: str) -> list[str]:
|
def splitlines(text: str) -> list[str]:
|
||||||
|
@ -249,21 +267,25 @@ def splitlines(text: str) -> list[str]:
|
||||||
i = j
|
i = j
|
||||||
return ss
|
return ss
|
||||||
|
|
||||||
|
|
||||||
# also recognize old Mac OS line endings
|
# also recognize old Mac OS line endings
|
||||||
def readlines(fd):
|
def readlines(fd):
|
||||||
return _strip_eols(splitlines(fd.read()))
|
return _strip_eols(splitlines(fd.read()))
|
||||||
|
|
||||||
|
|
||||||
# map an encoding name to its standard form
|
# map an encoding name to its standard form
|
||||||
def norm_encoding(e):
|
def norm_encoding(e):
|
||||||
if e is not None:
|
if e is not None:
|
||||||
return e.replace('-', '_').lower()
|
return e.replace('-', '_').lower()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def null_to_empty(s):
|
def null_to_empty(s):
|
||||||
if s is None:
|
if s is None:
|
||||||
s = ''
|
s = ''
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
# utility method to step advance an adjustment
|
# utility method to step advance an adjustment
|
||||||
def step_adjustment(adj, delta):
|
def step_adjustment(adj, delta):
|
||||||
v = adj.get_value() + delta
|
v = adj.get_value() + delta
|
||||||
|
|
|
@ -23,6 +23,7 @@ from diffuse import utils
|
||||||
from diffuse.vcs.folder_set import FolderSet
|
from diffuse.vcs.folder_set import FolderSet
|
||||||
from diffuse.vcs.vcs_interface import VcsInterface
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
|
|
||||||
|
|
||||||
# Bazaar support
|
# Bazaar support
|
||||||
class Bzr(VcsInterface):
|
class Bzr(VcsInterface):
|
||||||
def getFileTemplate(self, prefs, name):
|
def getFileTemplate(self, prefs, name):
|
||||||
|
@ -30,13 +31,13 @@ class Bzr(VcsInterface):
|
||||||
left = name + '.OTHER'
|
left = name + '.OTHER'
|
||||||
right = name + '.THIS'
|
right = name + '.THIS'
|
||||||
if os.path.isfile(left) and os.path.isfile(right):
|
if os.path.isfile(left) and os.path.isfile(right):
|
||||||
return [ (left, None), (name, None), (right, None) ]
|
return [(left, None), (name, None), (right, None)]
|
||||||
# default case
|
# default case
|
||||||
return [ (name, '-1'), (name, None) ]
|
return [(name, '-1'), (name, None)]
|
||||||
|
|
||||||
def getCommitTemplate(self, prefs, rev, names):
|
def getCommitTemplate(self, prefs, rev, names):
|
||||||
# build command
|
# build command
|
||||||
args = [ prefs.getString('bzr_bin'), 'log', '-v', '-r', rev ]
|
args = [prefs.getString('bzr_bin'), 'log', '-v', '-r', rev]
|
||||||
# build list of interesting files
|
# build list of interesting files
|
||||||
pwd, isabs = os.path.abspath(os.curdir), False
|
pwd, isabs = os.path.abspath(os.curdir), False
|
||||||
for name in names:
|
for name in names:
|
||||||
|
@ -62,7 +63,7 @@ class Bzr(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
added[k] = [ (None, None), (k, rev) ]
|
added[k] = [(None, None), (k, rev)]
|
||||||
elif s.startswith('modified:'):
|
elif s.startswith('modified:'):
|
||||||
# modified files
|
# modified files
|
||||||
while i < n and ss[i].startswith(' '):
|
while i < n and ss[i].startswith(' '):
|
||||||
|
@ -73,7 +74,7 @@ class Bzr(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
modified[k] = [ (k, prev), (k, rev) ]
|
modified[k] = [(k, prev), (k, rev)]
|
||||||
elif s.startswith('removed:'):
|
elif s.startswith('removed:'):
|
||||||
# removed files
|
# removed files
|
||||||
while i < n and ss[i].startswith(' '):
|
while i < n and ss[i].startswith(' '):
|
||||||
|
@ -84,7 +85,7 @@ class Bzr(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
removed[k] = [ (k, prev), (None, None) ]
|
removed[k] = [(k, prev), (None, None)]
|
||||||
elif s.startswith('renamed:'):
|
elif s.startswith('renamed:'):
|
||||||
# renamed files
|
# renamed files
|
||||||
while i < n and ss[i].startswith(' '):
|
while i < n and ss[i].startswith(' '):
|
||||||
|
@ -100,7 +101,7 @@ class Bzr(VcsInterface):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k0 = utils.relpath(pwd, k0)
|
k0 = utils.relpath(pwd, k0)
|
||||||
k1 = utils.relpath(pwd, k1)
|
k1 = utils.relpath(pwd, k1)
|
||||||
renamed[k1] = [ (k0, prev), (k1, rev) ]
|
renamed[k1] = [(k0, prev), (k1, rev)]
|
||||||
# sort the results
|
# sort the results
|
||||||
result, r = [], set()
|
result, r = [], set()
|
||||||
for m in removed, added, modified, renamed:
|
for m in removed, added, modified, renamed:
|
||||||
|
@ -113,7 +114,7 @@ class Bzr(VcsInterface):
|
||||||
|
|
||||||
def getFolderTemplate(self, prefs, names):
|
def getFolderTemplate(self, prefs, names):
|
||||||
# build command
|
# build command
|
||||||
args = [ prefs.getString('bzr_bin'), 'status', '-SV' ]
|
args = [prefs.getString('bzr_bin'), 'status', '-SV']
|
||||||
# build list of interesting files
|
# build list of interesting files
|
||||||
pwd, isabs = os.path.abspath(os.curdir), False
|
pwd, isabs = os.path.abspath(os.curdir), False
|
||||||
for name in names:
|
for name in names:
|
||||||
|
@ -136,7 +137,7 @@ class Bzr(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
removed[k] = [ (k, prev), (None, None) ]
|
removed[k] = [(k, prev), (None, None)]
|
||||||
elif y == 'N':
|
elif y == 'N':
|
||||||
# added
|
# added
|
||||||
k = prefs.convertToNativePath(k)
|
k = prefs.convertToNativePath(k)
|
||||||
|
@ -145,7 +146,7 @@ class Bzr(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
added[k] = [ (None, None), (k, None) ]
|
added[k] = [(None, None), (k, None)]
|
||||||
elif y == 'M':
|
elif y == 'M':
|
||||||
# modified or merge conflict
|
# modified or merge conflict
|
||||||
k = prefs.convertToNativePath(k)
|
k = prefs.convertToNativePath(k)
|
||||||
|
@ -168,7 +169,7 @@ class Bzr(VcsInterface):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k0 = utils.relpath(pwd, k0)
|
k0 = utils.relpath(pwd, k0)
|
||||||
k1 = utils.relpath(pwd, k1)
|
k1 = utils.relpath(pwd, k1)
|
||||||
renamed[k1] = [ (k0, prev), (k1, None) ]
|
renamed[k1] = [(k0, prev), (k1, None)]
|
||||||
# sort the results
|
# sort the results
|
||||||
result, r = [], set()
|
result, r = [], set()
|
||||||
for m in removed, added, modified, renamed:
|
for m in removed, added, modified, renamed:
|
||||||
|
|
|
@ -23,10 +23,11 @@ from diffuse import utils
|
||||||
from diffuse.vcs.folder_set import FolderSet
|
from diffuse.vcs.folder_set import FolderSet
|
||||||
from diffuse.vcs.vcs_interface import VcsInterface
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
|
|
||||||
|
|
||||||
# CVS support
|
# CVS support
|
||||||
class Cvs(VcsInterface):
|
class Cvs(VcsInterface):
|
||||||
def getFileTemplate(self, prefs, name):
|
def getFileTemplate(self, prefs, name):
|
||||||
return [ (name, 'BASE'), (name, None) ]
|
return [(name, 'BASE'), (name, None)]
|
||||||
|
|
||||||
def getCommitTemplate(self, prefs, rev, names):
|
def getCommitTemplate(self, prefs, rev, names):
|
||||||
result = []
|
result = []
|
||||||
|
@ -45,14 +46,14 @@ class Cvs(VcsInterface):
|
||||||
k0 = None
|
k0 = None
|
||||||
else:
|
else:
|
||||||
k0 = k
|
k0 = k
|
||||||
result.append([ (k0, prev), (k, rev) ])
|
result.append([(k0, prev), (k, rev)])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
utils.logError(_('Error parsing revision %s.') % (rev, ))
|
utils.logError(_('Error parsing revision %s.') % (rev, ))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def getFolderTemplate(self, prefs, names):
|
def getFolderTemplate(self, prefs, names):
|
||||||
# build command
|
# build command
|
||||||
args = [ prefs.getString('cvs_bin'), '-nq', 'update', '-R' ]
|
args = [prefs.getString('cvs_bin'), '-nq', 'update', '-R']
|
||||||
# build list of interesting files
|
# build list of interesting files
|
||||||
pwd, isabs = os.path.abspath(os.curdir), False
|
pwd, isabs = os.path.abspath(os.curdir), False
|
||||||
for name in names:
|
for name in names:
|
||||||
|
@ -72,15 +73,15 @@ class Cvs(VcsInterface):
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
if s[0] == 'R':
|
if s[0] == 'R':
|
||||||
# removed
|
# removed
|
||||||
modified[k] = [ (k, prev), (None, None) ]
|
modified[k] = [(k, prev), (None, None)]
|
||||||
elif s[0] == 'A':
|
elif s[0] == 'A':
|
||||||
# added
|
# added
|
||||||
modified[k] = [ (None, None), (k, None) ]
|
modified[k] = [(None, None), (k, None)]
|
||||||
else:
|
else:
|
||||||
# modified
|
# modified
|
||||||
modified[k] = [ (k, prev), (k, None) ]
|
modified[k] = [(k, prev), (k, None)]
|
||||||
# sort the results
|
# sort the results
|
||||||
return [ modified[k] for k in sorted(modified.keys()) ]
|
return [modified[k] for k in sorted(modified.keys())]
|
||||||
|
|
||||||
def getRevision(self, prefs, name, rev):
|
def getRevision(self, prefs, name, rev):
|
||||||
if rev == 'BASE' and not os.path.exists(name):
|
if rev == 'BASE' and not os.path.exists(name):
|
||||||
|
@ -93,7 +94,8 @@ class Cvs(VcsInterface):
|
||||||
utils.safeRelativePath(self.root, name, prefs, 'cvs_cygwin')
|
utils.safeRelativePath(self.root, name, prefs, 'cvs_cygwin')
|
||||||
],
|
],
|
||||||
prefs,
|
prefs,
|
||||||
'cvs_bash'):
|
'cvs_bash'
|
||||||
|
):
|
||||||
if s.startswith(' Working revision:\t-'):
|
if s.startswith(' Working revision:\t-'):
|
||||||
rev = s.split('\t')[1][1:]
|
rev = s.split('\t')[1][1:]
|
||||||
return utils.popenRead(
|
return utils.popenRead(
|
||||||
|
|
|
@ -23,15 +23,16 @@ from diffuse import utils
|
||||||
from diffuse.vcs.folder_set import FolderSet
|
from diffuse.vcs.folder_set import FolderSet
|
||||||
from diffuse.vcs.vcs_interface import VcsInterface
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
|
|
||||||
|
|
||||||
# Darcs support
|
# Darcs support
|
||||||
class Darcs(VcsInterface):
|
class Darcs(VcsInterface):
|
||||||
def getFileTemplate(self, prefs, name):
|
def getFileTemplate(self, prefs, name):
|
||||||
return [ (name, ''), (name, None) ]
|
return [(name, ''), (name, None)]
|
||||||
|
|
||||||
def _getCommitTemplate(self, prefs, names, rev):
|
def _getCommitTemplate(self, prefs, names, rev):
|
||||||
mods = (rev is None)
|
mods = (rev is None)
|
||||||
# build command
|
# build command
|
||||||
args = [ prefs.getString('darcs_bin') ]
|
args = [prefs.getString('darcs_bin')]
|
||||||
if mods:
|
if mods:
|
||||||
args.extend(['whatsnew', '-s'])
|
args.extend(['whatsnew', '-s'])
|
||||||
else:
|
else:
|
||||||
|
@ -84,7 +85,7 @@ class Darcs(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
removed[k] = [ (k, prev), (None, None) ]
|
removed[k] = [(k, prev), (None, None)]
|
||||||
elif x == 'A':
|
elif x == 'A':
|
||||||
# added
|
# added
|
||||||
k = prefs.convertToNativePath(s[2:])
|
k = prefs.convertToNativePath(s[2:])
|
||||||
|
@ -93,7 +94,7 @@ class Darcs(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
added[k] = [ (None, None), (k, rev) ]
|
added[k] = [(None, None), (k, rev)]
|
||||||
elif x == 'M':
|
elif x == 'M':
|
||||||
# modified
|
# modified
|
||||||
k = prefs.convertToNativePath(s[2:].split(' ')[0])
|
k = prefs.convertToNativePath(s[2:].split(' ')[0])
|
||||||
|
@ -103,7 +104,7 @@ class Darcs(VcsInterface):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
if k not in renamed:
|
if k not in renamed:
|
||||||
modified[k] = [ (k, prev), (k, rev) ]
|
modified[k] = [(k, prev), (k, rev)]
|
||||||
elif x == ' ':
|
elif x == ' ':
|
||||||
# renamed
|
# renamed
|
||||||
k = s[1:].split(' -> ')
|
k = s[1:].split(' -> ')
|
||||||
|
@ -117,7 +118,7 @@ class Darcs(VcsInterface):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k0 = utils.relpath(pwd, k0)
|
k0 = utils.relpath(pwd, k0)
|
||||||
k1 = utils.relpath(pwd, k1)
|
k1 = utils.relpath(pwd, k1)
|
||||||
renamed[k1] = [ (k0, prev), (k1, rev) ]
|
renamed[k1] = [(k0, prev), (k1, rev)]
|
||||||
# sort the results
|
# sort the results
|
||||||
result, r = [], set()
|
result, r = [], set()
|
||||||
for m in added, modified, removed, renamed:
|
for m in added, modified, removed, renamed:
|
||||||
|
@ -135,10 +136,10 @@ class Darcs(VcsInterface):
|
||||||
return self._getCommitTemplate(prefs, names, None)
|
return self._getCommitTemplate(prefs, names, None)
|
||||||
|
|
||||||
def getRevision(self, prefs, name, rev):
|
def getRevision(self, prefs, name, rev):
|
||||||
args = [ prefs.getString('darcs_bin'), 'show', 'contents' ]
|
args = [prefs.getString('darcs_bin'), 'show', 'contents']
|
||||||
try:
|
try:
|
||||||
args.extend([ '-n', str(int(rev)) ])
|
args.extend(['-n', str(int(rev))])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
args.extend([ '-h', rev ])
|
args.extend(['-h', rev])
|
||||||
args.append(utils.safeRelativePath(self.root, name, prefs, 'darcs_cygwin'))
|
args.append(utils.safeRelativePath(self.root, name, prefs, 'darcs_cygwin'))
|
||||||
return utils.popenRead(self.root, args, prefs, 'darcs_bash')
|
return utils.popenRead(self.root, args, prefs, 'darcs_bash')
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class FolderSet:
|
class FolderSet:
|
||||||
'''Utility class to help support Git and Monotone.
|
'''Utility class to help support Git and Monotone.
|
||||||
Represents a set of files and folders of interest for "git status" or
|
Represents a set of files and folders of interest for "git status" or
|
||||||
|
|
|
@ -23,14 +23,15 @@ from diffuse import utils
|
||||||
from diffuse.vcs.folder_set import FolderSet
|
from diffuse.vcs.folder_set import FolderSet
|
||||||
from diffuse.vcs.vcs_interface import VcsInterface
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
|
|
||||||
|
|
||||||
# Git support
|
# Git support
|
||||||
class Git(VcsInterface):
|
class Git(VcsInterface):
|
||||||
def getFileTemplate(self, prefs, name):
|
def getFileTemplate(self, prefs, name):
|
||||||
return [ (name, 'HEAD'), (name, None) ]
|
return [(name, 'HEAD'), (name, None)]
|
||||||
|
|
||||||
def getCommitTemplate(self, prefs, rev, names):
|
def getCommitTemplate(self, prefs, rev, names):
|
||||||
# build command
|
# build command
|
||||||
args = [ prefs.getString('git_bin'), 'show', '--pretty=format:', '--name-status', rev ]
|
args = [prefs.getString('git_bin'), 'show', '--pretty=format:', '--name-status', rev]
|
||||||
# build list of interesting files
|
# build list of interesting files
|
||||||
pwd = os.path.abspath(os.curdir)
|
pwd = os.path.abspath(os.curdir)
|
||||||
isabs = False
|
isabs = False
|
||||||
|
@ -50,15 +51,15 @@ class Git(VcsInterface):
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
if s[0] == 'D':
|
if s[0] == 'D':
|
||||||
# removed
|
# removed
|
||||||
modified[k] = [ (k, prev), (None, None) ]
|
modified[k] = [(k, prev), (None, None)]
|
||||||
elif s[0] == 'A':
|
elif s[0] == 'A':
|
||||||
# added
|
# added
|
||||||
modified[k] = [ (None, None), (k, rev) ]
|
modified[k] = [(None, None), (k, rev)]
|
||||||
else:
|
else:
|
||||||
# modified
|
# modified
|
||||||
modified[k] = [ (k, prev), (k, rev) ]
|
modified[k] = [(k, prev), (k, rev)]
|
||||||
# sort the results
|
# sort the results
|
||||||
return [ modified[k] for k in sorted(modified.keys()) ]
|
return [modified[k] for k in sorted(modified.keys())]
|
||||||
|
|
||||||
def _extractPath(self, s, prefs):
|
def _extractPath(self, s, prefs):
|
||||||
return os.path.join(self.root, prefs.convertToNativePath(s.strip()))
|
return os.path.join(self.root, prefs.convertToNativePath(s.strip()))
|
||||||
|
@ -98,7 +99,7 @@ class Git(VcsInterface):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k0 = utils.relpath(pwd, k0)
|
k0 = utils.relpath(pwd, k0)
|
||||||
k1 = utils.relpath(pwd, k1)
|
k1 = utils.relpath(pwd, k1)
|
||||||
renamed[k1] = [ (k0, prev), (k1, None) ]
|
renamed[k1] = [(k0, prev), (k1, None)]
|
||||||
elif x == 'U' or y == 'U' or (x == 'D' and y == 'D'):
|
elif x == 'U' or y == 'U' or (x == 'D' and y == 'D'):
|
||||||
# merge conflict
|
# merge conflict
|
||||||
k = self._extractPath(k, prefs)
|
k = self._extractPath(k, prefs)
|
||||||
|
@ -106,9 +107,9 @@ class Git(VcsInterface):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
if x == 'D':
|
if x == 'D':
|
||||||
panes = [ (None, None) ]
|
panes = [(None, None)]
|
||||||
else:
|
else:
|
||||||
panes = [ (k, ':2') ]
|
panes = [(k, ':2')]
|
||||||
panes.append((k, None))
|
panes.append((k, None))
|
||||||
if y == 'D':
|
if y == 'D':
|
||||||
panes.append((None, None))
|
panes.append((None, None))
|
||||||
|
@ -124,9 +125,9 @@ class Git(VcsInterface):
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
if x == 'A':
|
if x == 'A':
|
||||||
# added
|
# added
|
||||||
panes = [ (None, None) ]
|
panes = [(None, None)]
|
||||||
else:
|
else:
|
||||||
panes = [ (k, prev) ]
|
panes = [(k, prev)]
|
||||||
# staged changes
|
# staged changes
|
||||||
if x == 'D':
|
if x == 'D':
|
||||||
panes.append((None, None))
|
panes.append((None, None))
|
||||||
|
|
|
@ -23,6 +23,7 @@ from diffuse import utils
|
||||||
from diffuse.vcs.folder_set import FolderSet
|
from diffuse.vcs.folder_set import FolderSet
|
||||||
from diffuse.vcs.vcs_interface import VcsInterface
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
|
|
||||||
|
|
||||||
# Mercurial support
|
# Mercurial support
|
||||||
class Hg(VcsInterface):
|
class Hg(VcsInterface):
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
|
@ -34,7 +35,7 @@ class Hg(VcsInterface):
|
||||||
if self.working_rev is None:
|
if self.working_rev is None:
|
||||||
ss = utils.popenReadLines(
|
ss = utils.popenReadLines(
|
||||||
self.root,
|
self.root,
|
||||||
[ prefs.getString('hg_bin'), 'id', '-i', '-t' ],
|
[prefs.getString('hg_bin'), 'id', '-i', '-t'],
|
||||||
prefs,
|
prefs,
|
||||||
'hg_bash')
|
'hg_bash')
|
||||||
if len(ss) != 1:
|
if len(ss) != 1:
|
||||||
|
@ -49,11 +50,11 @@ class Hg(VcsInterface):
|
||||||
return f'p1({rev})'
|
return f'p1({rev})'
|
||||||
|
|
||||||
def getFileTemplate(self, prefs, name):
|
def getFileTemplate(self, prefs, name):
|
||||||
return [ (name, self._getPreviousRevision(prefs, None)), (name, None) ]
|
return [(name, self._getPreviousRevision(prefs, None)), (name, None)]
|
||||||
|
|
||||||
def _getCommitTemplate(self, prefs, names, cmd, rev):
|
def _getCommitTemplate(self, prefs, names, cmd, rev):
|
||||||
# build command
|
# build command
|
||||||
args = [ prefs.getString('hg_bin') ]
|
args = [prefs.getString('hg_bin')]
|
||||||
args.extend(cmd)
|
args.extend(cmd)
|
||||||
# build list of interesting files
|
# build list of interesting files
|
||||||
pwd, isabs = os.path.abspath(os.curdir), False
|
pwd, isabs = os.path.abspath(os.curdir), False
|
||||||
|
@ -74,25 +75,25 @@ class Hg(VcsInterface):
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
if s[0] == 'R':
|
if s[0] == 'R':
|
||||||
# removed
|
# removed
|
||||||
modified[k] = [ (k, prev), (None, None) ]
|
modified[k] = [(k, prev), (None, None)]
|
||||||
elif s[0] == 'A':
|
elif s[0] == 'A':
|
||||||
# added
|
# added
|
||||||
modified[k] = [ (None, None), (k, rev) ]
|
modified[k] = [(None, None), (k, rev)]
|
||||||
else:
|
else:
|
||||||
# modified or merge conflict
|
# modified or merge conflict
|
||||||
modified[k] = [ (k, prev), (k, rev) ]
|
modified[k] = [(k, prev), (k, rev)]
|
||||||
# sort the results
|
# sort the results
|
||||||
return [ modified[k] for k in sorted(modified.keys()) ]
|
return [modified[k] for k in sorted(modified.keys())]
|
||||||
|
|
||||||
def getCommitTemplate(self, prefs, rev, names):
|
def getCommitTemplate(self, prefs, rev, names):
|
||||||
return self._getCommitTemplate(
|
return self._getCommitTemplate(
|
||||||
prefs,
|
prefs,
|
||||||
names,
|
names,
|
||||||
[ 'log', '--template', 'A\t{file_adds}\nM\t{file_mods}\nR\t{file_dels}\n', '-r', rev ],
|
['log', '--template', 'A\t{file_adds}\nM\t{file_mods}\nR\t{file_dels}\n', '-r', rev],
|
||||||
rev)
|
rev)
|
||||||
|
|
||||||
def getFolderTemplate(self, prefs, names):
|
def getFolderTemplate(self, prefs, names):
|
||||||
return self._getCommitTemplate(prefs, names, [ 'status', '-q' ], None)
|
return self._getCommitTemplate(prefs, names, ['status', '-q'], None)
|
||||||
|
|
||||||
def getRevision(self, prefs, name, rev):
|
def getRevision(self, prefs, name, rev):
|
||||||
return utils.popenRead(
|
return utils.popenRead(
|
||||||
|
|
|
@ -24,23 +24,24 @@ from diffuse import utils
|
||||||
from diffuse.vcs.folder_set import FolderSet
|
from diffuse.vcs.folder_set import FolderSet
|
||||||
from diffuse.vcs.vcs_interface import VcsInterface
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
|
|
||||||
|
|
||||||
# Monotone support
|
# Monotone support
|
||||||
class Mtn(VcsInterface):
|
class Mtn(VcsInterface):
|
||||||
def getFileTemplate(self, prefs, name):
|
def getFileTemplate(self, prefs, name):
|
||||||
# FIXME: merge conflicts?
|
# FIXME: merge conflicts?
|
||||||
return [ (name, 'h:'), (name, None) ]
|
return [(name, 'h:'), (name, None)]
|
||||||
|
|
||||||
def getCommitTemplate(self, prefs, rev, names):
|
def getCommitTemplate(self, prefs, rev, names):
|
||||||
# build command
|
# build command
|
||||||
vcs_bin = prefs.getString('mtn_bin')
|
vcs_bin = prefs.getString('mtn_bin')
|
||||||
ss = utils.popenReadLines(
|
ss = utils.popenReadLines(
|
||||||
self.root,
|
self.root,
|
||||||
[ vcs_bin, 'automate', 'select', '-q', rev ],
|
[vcs_bin, 'automate', 'select', '-q', rev],
|
||||||
prefs,
|
prefs,
|
||||||
'mtn_bash')
|
'mtn_bash')
|
||||||
if len(ss) != 1:
|
if len(ss) != 1:
|
||||||
raise IOError('Ambiguous revision specifier')
|
raise IOError('Ambiguous revision specifier')
|
||||||
args = [ vcs_bin, 'automate', 'get_revision', ss[0] ]
|
args = [vcs_bin, 'automate', 'get_revision', ss[0]]
|
||||||
# build list of interesting files
|
# build list of interesting files
|
||||||
fs = FolderSet(names)
|
fs = FolderSet(names)
|
||||||
pwd, isabs = os.path.abspath(os.curdir), False
|
pwd, isabs = os.path.abspath(os.curdir), False
|
||||||
|
@ -94,9 +95,10 @@ class Mtn(VcsInterface):
|
||||||
removed_dirs = set()
|
removed_dirs = set()
|
||||||
for s in utils.popenReadLines(
|
for s in utils.popenReadLines(
|
||||||
self.root,
|
self.root,
|
||||||
[ vcs_bin, 'automate', 'get_manifest_of', prev ],
|
[vcs_bin, 'automate', 'get_manifest_of', prev],
|
||||||
prefs,
|
prefs,
|
||||||
'mtn_bash'):
|
'mtn_bash'
|
||||||
|
):
|
||||||
s = shlex.split(s)
|
s = shlex.split(s)
|
||||||
if len(s) > 1 and s[0] == 'dir':
|
if len(s) > 1 and s[0] == 'dir':
|
||||||
removed_dirs.add(s[1])
|
removed_dirs.add(s[1])
|
||||||
|
@ -117,12 +119,12 @@ class Mtn(VcsInterface):
|
||||||
k = removed[k]
|
k = removed[k]
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
result.append([ (k, prev), (None, None) ])
|
result.append([(k, prev), (None, None)])
|
||||||
elif k in added:
|
elif k in added:
|
||||||
k = added[k]
|
k = added[k]
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
result.append([ (None, None), (k, rev) ])
|
result.append([(None, None), (k, rev)])
|
||||||
else:
|
else:
|
||||||
if k in renamed:
|
if k in renamed:
|
||||||
arg1, k0, k1 = renamed[k]
|
arg1, k0, k1 = renamed[k]
|
||||||
|
@ -131,7 +133,7 @@ class Mtn(VcsInterface):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k0 = utils.relpath(pwd, k0)
|
k0 = utils.relpath(pwd, k0)
|
||||||
k1 = utils.relpath(pwd, k1)
|
k1 = utils.relpath(pwd, k1)
|
||||||
result.append([ (k0, prev), (k1, rev) ])
|
result.append([(k0, prev), (k1, rev)])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def getFolderTemplate(self, prefs, names):
|
def getFolderTemplate(self, prefs, names):
|
||||||
|
@ -173,7 +175,7 @@ class Mtn(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
removed[k] = [ (k, prev), (None, None) ]
|
removed[k] = [(k, prev), (None, None)]
|
||||||
processed = True
|
processed = True
|
||||||
if 'added' in s and 'file' in m.get('new_type', []):
|
if 'added' in s and 'file' in m.get('new_type', []):
|
||||||
# new file
|
# new file
|
||||||
|
@ -181,7 +183,7 @@ class Mtn(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
added[k] = [ (None, None), (k, None) ]
|
added[k] = [(None, None), (k, None)]
|
||||||
processed = True
|
processed = True
|
||||||
if (
|
if (
|
||||||
'rename_target' in s and
|
'rename_target' in s and
|
||||||
|
@ -195,7 +197,7 @@ class Mtn(VcsInterface):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k0 = utils.relpath(pwd, k0)
|
k0 = utils.relpath(pwd, k0)
|
||||||
k1 = utils.relpath(pwd, k1)
|
k1 = utils.relpath(pwd, k1)
|
||||||
renamed[k1] = [ (k0, prev), (k1, None) ]
|
renamed[k1] = [(k0, prev), (k1, None)]
|
||||||
processed = True
|
processed = True
|
||||||
if not processed and 'file' in m.get('fs_type', []):
|
if not processed and 'file' in m.get('fs_type', []):
|
||||||
# modified file or merge conflict
|
# modified file or merge conflict
|
||||||
|
@ -203,7 +205,7 @@ class Mtn(VcsInterface):
|
||||||
if fs.contains(k):
|
if fs.contains(k):
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
modified[k] = [ (k, prev), (k, None) ]
|
modified[k] = [(k, prev), (k, None)]
|
||||||
# sort the results
|
# sort the results
|
||||||
r = set()
|
r = set()
|
||||||
for m in removed, added, modified, renamed:
|
for m in removed, added, modified, renamed:
|
||||||
|
|
|
@ -22,6 +22,7 @@ import os
|
||||||
from diffuse import utils
|
from diffuse import utils
|
||||||
from diffuse.vcs.vcs_interface import VcsInterface
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
|
|
||||||
|
|
||||||
# RCS support
|
# RCS support
|
||||||
class Rcs(VcsInterface):
|
class Rcs(VcsInterface):
|
||||||
def getFileTemplate(self, prefs, name):
|
def getFileTemplate(self, prefs, name):
|
||||||
|
@ -35,7 +36,7 @@ class Rcs(VcsInterface):
|
||||||
for line in utils.popenReadLines(self.root, args, prefs, 'rcs_bash'):
|
for line in utils.popenReadLines(self.root, args, prefs, 'rcs_bash'):
|
||||||
if line.startswith('head: '):
|
if line.startswith('head: '):
|
||||||
rev = line[6:]
|
rev = line[6:]
|
||||||
return [ (name, rev), (name, None) ]
|
return [(name, rev), (name, None)]
|
||||||
|
|
||||||
def getCommitTemplate(self, prefs, rev, names):
|
def getCommitTemplate(self, prefs, rev, names):
|
||||||
result = []
|
result = []
|
||||||
|
@ -54,7 +55,7 @@ class Rcs(VcsInterface):
|
||||||
k0 = None
|
k0 = None
|
||||||
else:
|
else:
|
||||||
k0 = k
|
k0 = k
|
||||||
result.append([ (k0, prev), (k, rev) ])
|
result.append([(k0, prev), (k, rev)])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
utils.logError(_('Error parsing revision %s.') % (rev, ))
|
utils.logError(_('Error parsing revision %s.') % (rev, ))
|
||||||
return result
|
return result
|
||||||
|
@ -64,11 +65,11 @@ class Rcs(VcsInterface):
|
||||||
# os.sysconf() is only available on Unix
|
# os.sysconf() is only available on Unix
|
||||||
if hasattr(os, 'sysconf'):
|
if hasattr(os, 'sysconf'):
|
||||||
maxsize = os.sysconf('SC_ARG_MAX')
|
maxsize = os.sysconf('SC_ARG_MAX')
|
||||||
maxsize -= sum([ len(k) + len(v) + 2 for k, v in os.environ.items() ])
|
maxsize -= sum([len(k) + len(v) + 2 for k, v in os.environ.items()])
|
||||||
else:
|
else:
|
||||||
# assume the Window's limit to CreateProcess()
|
# assume the Window's limit to CreateProcess()
|
||||||
maxsize = 32767
|
maxsize = 32767
|
||||||
maxsize -= sum([ len(k) + 1 for k in cmd ])
|
maxsize -= sum([len(k) + 1 for k in cmd])
|
||||||
|
|
||||||
ss = []
|
ss = []
|
||||||
i, s, a = 0, 0, []
|
i, s, a = 0, 0, []
|
||||||
|
@ -91,14 +92,14 @@ class Rcs(VcsInterface):
|
||||||
|
|
||||||
def getFolderTemplate(self, prefs, names):
|
def getFolderTemplate(self, prefs, names):
|
||||||
# build command
|
# build command
|
||||||
cmd = [ prefs.getString('rcs_bin_rlog'), '-L', '-h' ]
|
cmd = [prefs.getString('rcs_bin_rlog'), '-L', '-h']
|
||||||
# build list of interesting files
|
# build list of interesting files
|
||||||
pwd, isabs = os.path.abspath(os.curdir), False
|
pwd, isabs = os.path.abspath(os.curdir), False
|
||||||
r = []
|
r = []
|
||||||
for k in names:
|
for k in names:
|
||||||
if os.path.isdir(k):
|
if os.path.isdir(k):
|
||||||
# the user specified a folder
|
# the user specified a folder
|
||||||
n, ex = [ k ], True
|
n, ex = [k], True
|
||||||
while len(n) > 0:
|
while len(n) > 0:
|
||||||
s = n.pop()
|
s = n.pop()
|
||||||
recurse = os.path.isdir(os.path.join(s, 'RCS'))
|
recurse = os.path.isdir(os.path.join(s, 'RCS'))
|
||||||
|
@ -135,7 +136,7 @@ class Rcs(VcsInterface):
|
||||||
r.append(k)
|
r.append(k)
|
||||||
for k in r:
|
for k in r:
|
||||||
isabs |= os.path.isabs(k)
|
isabs |= os.path.isabs(k)
|
||||||
args = [ utils.safeRelativePath(self.root, k, prefs, 'rcs_cygwin') for k in r ]
|
args = [utils.safeRelativePath(self.root, k, prefs, 'rcs_cygwin') for k in r]
|
||||||
# run command
|
# run command
|
||||||
r, k = {}, ''
|
r, k = {}, ''
|
||||||
for line in self._popen_xargs_readlines(cmd, args, prefs, 'rcs_bash'):
|
for line in self._popen_xargs_readlines(cmd, args, prefs, 'rcs_bash'):
|
||||||
|
@ -148,7 +149,7 @@ class Rcs(VcsInterface):
|
||||||
elif line.startswith('head: '):
|
elif line.startswith('head: '):
|
||||||
r[k] = line[6:]
|
r[k] = line[6:]
|
||||||
# sort the results
|
# sort the results
|
||||||
return [ [ (k, r[k]), (k, None) ] for k in sorted(r.keys()) ]
|
return [[(k, r[k]), (k, None)] for k in sorted(r.keys())]
|
||||||
|
|
||||||
def getRevision(self, prefs, name, rev):
|
def getRevision(self, prefs, name, rev):
|
||||||
return utils.popenRead(
|
return utils.popenRead(
|
||||||
|
|
|
@ -22,6 +22,7 @@ import os
|
||||||
from diffuse import utils
|
from diffuse import utils
|
||||||
from diffuse.vcs.svn import Svn
|
from diffuse.vcs.svn import Svn
|
||||||
|
|
||||||
|
|
||||||
class Svk(Svn):
|
class Svk(Svn):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _getVcs():
|
def _getVcs():
|
||||||
|
|
|
@ -24,6 +24,7 @@ from diffuse import utils
|
||||||
from diffuse.vcs.folder_set import FolderSet
|
from diffuse.vcs.folder_set import FolderSet
|
||||||
from diffuse.vcs.vcs_interface import VcsInterface
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
|
|
||||||
|
|
||||||
# Subversion support
|
# Subversion support
|
||||||
# SVK support subclasses from this
|
# SVK support subclasses from this
|
||||||
class Svn(VcsInterface):
|
class Svn(VcsInterface):
|
||||||
|
@ -60,7 +61,7 @@ class Svn(VcsInterface):
|
||||||
if self.url is None:
|
if self.url is None:
|
||||||
vcs, prefix = self._getVcs(), self._getURLPrefix()
|
vcs, prefix = self._getVcs(), self._getURLPrefix()
|
||||||
n = len(prefix)
|
n = len(prefix)
|
||||||
args = [ prefs.getString(vcs + '_bin'), 'info' ]
|
args = [prefs.getString(vcs + '_bin'), 'info']
|
||||||
for s in utils.popenReadLines(self.root, args, prefs, vcs + '_bash'):
|
for s in utils.popenReadLines(self.root, args, prefs, vcs + '_bash'):
|
||||||
if s.startswith(prefix):
|
if s.startswith(prefix):
|
||||||
self.url = s[n:]
|
self.url = s[n:]
|
||||||
|
@ -74,15 +75,15 @@ class Svn(VcsInterface):
|
||||||
left = glob.glob(escaped_name + '.merge-left.r*')
|
left = glob.glob(escaped_name + '.merge-left.r*')
|
||||||
right = glob.glob(escaped_name + '.merge-right.r*')
|
right = glob.glob(escaped_name + '.merge-right.r*')
|
||||||
if len(left) > 0 and len(right) > 0:
|
if len(left) > 0 and len(right) > 0:
|
||||||
return [ (left[-1], None), (name, None), (right[-1], None) ]
|
return [(left[-1], None), (name, None), (right[-1], None)]
|
||||||
# update conflict
|
# update conflict
|
||||||
left = sorted(glob.glob(escaped_name + '.r*'))
|
left = sorted(glob.glob(escaped_name + '.r*'))
|
||||||
right = glob.glob(escaped_name + '.mine')
|
right = glob.glob(escaped_name + '.mine')
|
||||||
right.extend(glob.glob(escaped_name + '.working'))
|
right.extend(glob.glob(escaped_name + '.working'))
|
||||||
if len(left) > 0 and len(right) > 0:
|
if len(left) > 0 and len(right) > 0:
|
||||||
return [ (left[-1], None), (name, None), (right[0], None) ]
|
return [(left[-1], None), (name, None), (right[0], None)]
|
||||||
# default case
|
# default case
|
||||||
return [ (name, self._getPreviousRevision(None)), (name, None) ]
|
return [(name, self._getPreviousRevision(None)), (name, None)]
|
||||||
|
|
||||||
def _getCommitTemplate(self, prefs, rev, names):
|
def _getCommitTemplate(self, prefs, rev, names):
|
||||||
result = []
|
result = []
|
||||||
|
@ -96,9 +97,9 @@ class Svn(VcsInterface):
|
||||||
vcs = self._getVcs()
|
vcs = self._getVcs()
|
||||||
vcs_bin, vcs_bash = prefs.getString(vcs + '_bin'), vcs + '_bash'
|
vcs_bin, vcs_bash = prefs.getString(vcs + '_bin'), vcs + '_bash'
|
||||||
if rev is None:
|
if rev is None:
|
||||||
args = [ vcs_bin, 'status', '-q' ]
|
args = [vcs_bin, 'status', '-q']
|
||||||
else:
|
else:
|
||||||
args = [ vcs_bin, 'diff', '--summarize', '-c', rev ]
|
args = [vcs_bin, 'diff', '--summarize', '-c', rev]
|
||||||
# build list of interesting files
|
# build list of interesting files
|
||||||
pwd, isabs = os.path.abspath(os.curdir), False
|
pwd, isabs = os.path.abspath(os.curdir), False
|
||||||
for name in names:
|
for name in names:
|
||||||
|
@ -129,7 +130,7 @@ class Svn(VcsInterface):
|
||||||
k = os.path.join(self.root, k)
|
k = os.path.join(self.root, k)
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
modified[k] = [ (k, prev), (k, rev) ]
|
modified[k] = [(k, prev), (k, rev)]
|
||||||
elif v == 'C':
|
elif v == 'C':
|
||||||
# merge conflict
|
# merge conflict
|
||||||
modified[k] = self.getFileTemplate(prefs, k)
|
modified[k] = self.getFileTemplate(prefs, k)
|
||||||
|
@ -146,7 +147,7 @@ class Svn(VcsInterface):
|
||||||
k = os.path.join(self.root, k)
|
k = os.path.join(self.root, k)
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
added[k] = [ (None, None), (k, None) ]
|
added[k] = [(None, None), (k, None)]
|
||||||
else:
|
else:
|
||||||
m = {}
|
m = {}
|
||||||
for k in added:
|
for k in added:
|
||||||
|
@ -181,7 +182,7 @@ class Svn(VcsInterface):
|
||||||
k = os.path.join(self.root, os.path.join(p, s))
|
k = os.path.join(self.root, os.path.join(p, s))
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
added[k] = [ (None, None), (k, rev) ]
|
added[k] = [(None, None), (k, rev)]
|
||||||
# determine if removed items are files or directories
|
# determine if removed items are files or directories
|
||||||
if prev == 'BASE':
|
if prev == 'BASE':
|
||||||
m, removed = removed, {}
|
m, removed = removed, {}
|
||||||
|
@ -191,7 +192,7 @@ class Svn(VcsInterface):
|
||||||
k = os.path.join(self.root, k)
|
k = os.path.join(self.root, k)
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
removed[k] = [ (k, prev), (None, None) ]
|
removed[k] = [(k, prev), (None, None)]
|
||||||
else:
|
else:
|
||||||
m = {}
|
m = {}
|
||||||
for k in removed:
|
for k in removed:
|
||||||
|
@ -224,7 +225,7 @@ class Svn(VcsInterface):
|
||||||
k = os.path.join(self.root, os.path.join(p, s))
|
k = os.path.join(self.root, os.path.join(p, s))
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
removed[k] = [ (k, prev), (None, None) ]
|
removed[k] = [(k, prev), (None, None)]
|
||||||
# recursively find all unreported removed files
|
# recursively find all unreported removed files
|
||||||
while removed_dir:
|
while removed_dir:
|
||||||
tmp = removed_dir
|
tmp = removed_dir
|
||||||
|
@ -250,7 +251,7 @@ class Svn(VcsInterface):
|
||||||
k = os.path.join(self.root, os.path.join(p, s))
|
k = os.path.join(self.root, os.path.join(p, s))
|
||||||
if not isabs:
|
if not isabs:
|
||||||
k = utils.relpath(pwd, k)
|
k = utils.relpath(pwd, k)
|
||||||
removed[k] = [ (k, prev), (None, None) ]
|
removed[k] = [(k, prev), (None, None)]
|
||||||
# sort the results
|
# sort the results
|
||||||
r = set()
|
r = set()
|
||||||
for m in removed, added, modified:
|
for m in removed, added, modified:
|
||||||
|
@ -269,7 +270,7 @@ class Svn(VcsInterface):
|
||||||
|
|
||||||
def getRevision(self, prefs, name, rev):
|
def getRevision(self, prefs, name, rev):
|
||||||
vcs_bin = prefs.getString('svn_bin')
|
vcs_bin = prefs.getString('svn_bin')
|
||||||
if rev in [ 'BASE', 'COMMITTED', 'PREV' ]:
|
if rev in ['BASE', 'COMMITTED', 'PREV']:
|
||||||
return utils.popenRead(
|
return utils.popenRead(
|
||||||
self.root,
|
self.root,
|
||||||
[
|
[
|
||||||
|
|
|
@ -31,6 +31,7 @@ from diffuse.vcs.rcs import Rcs
|
||||||
from diffuse.vcs.svk import Svk
|
from diffuse.vcs.svk import Svk
|
||||||
from diffuse.vcs.svn import Svn
|
from diffuse.vcs.svn import Svn
|
||||||
|
|
||||||
|
|
||||||
class VcsRegistry:
|
class VcsRegistry:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# initialise the VCS objects
|
# initialise the VCS objects
|
||||||
|
@ -74,17 +75,21 @@ def _find_parent_dir_with(path, dir_name):
|
||||||
break
|
break
|
||||||
path = newpath
|
path = newpath
|
||||||
|
|
||||||
|
|
||||||
def _get_bzr_repo(path, prefs):
|
def _get_bzr_repo(path, prefs):
|
||||||
p = _find_parent_dir_with(path, '.bzr')
|
p = _find_parent_dir_with(path, '.bzr')
|
||||||
return Bzr(p) if p else None
|
return Bzr(p) if p else None
|
||||||
|
|
||||||
|
|
||||||
def _get_cvs_repo(path, prefs):
|
def _get_cvs_repo(path, prefs):
|
||||||
return Cvs(path) if os.path.isdir(os.path.join(path, 'CVS')) else None
|
return Cvs(path) if os.path.isdir(os.path.join(path, 'CVS')) else None
|
||||||
|
|
||||||
|
|
||||||
def _get_darcs_repo(path, prefs):
|
def _get_darcs_repo(path, prefs):
|
||||||
p = _find_parent_dir_with(path, '_darcs')
|
p = _find_parent_dir_with(path, '_darcs')
|
||||||
return Darcs(p) if p else None
|
return Darcs(p) if p else None
|
||||||
|
|
||||||
|
|
||||||
def _get_git_repo(path, prefs):
|
def _get_git_repo(path, prefs):
|
||||||
if 'GIT_DIR' in os.environ:
|
if 'GIT_DIR' in os.environ:
|
||||||
try:
|
try:
|
||||||
|
@ -127,14 +132,17 @@ def _get_git_repo(path, prefs):
|
||||||
break
|
break
|
||||||
path = newpath
|
path = newpath
|
||||||
|
|
||||||
|
|
||||||
def _get_hg_repo(path, prefs):
|
def _get_hg_repo(path, prefs):
|
||||||
p = _find_parent_dir_with(path, '.hg')
|
p = _find_parent_dir_with(path, '.hg')
|
||||||
return Hg(p) if p else None
|
return Hg(p) if p else None
|
||||||
|
|
||||||
|
|
||||||
def _get_mtn_repo(path, prefs):
|
def _get_mtn_repo(path, prefs):
|
||||||
p = _find_parent_dir_with(path, '_MTN')
|
p = _find_parent_dir_with(path, '_MTN')
|
||||||
return Mtn(p) if p else None
|
return Mtn(p) if p else None
|
||||||
|
|
||||||
|
|
||||||
def _get_rcs_repo(path, prefs):
|
def _get_rcs_repo(path, prefs):
|
||||||
if os.path.isdir(os.path.join(path, 'RCS')):
|
if os.path.isdir(os.path.join(path, 'RCS')):
|
||||||
return Rcs(path)
|
return Rcs(path)
|
||||||
|
@ -151,10 +159,12 @@ def _get_rcs_repo(path, prefs):
|
||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _get_svn_repo(path, prefs):
|
def _get_svn_repo(path, prefs):
|
||||||
p = _find_parent_dir_with(path, '.svn')
|
p = _find_parent_dir_with(path, '.svn')
|
||||||
return Svn(p) if p else None
|
return Svn(p) if p else None
|
||||||
|
|
||||||
|
|
||||||
def _get_svk_repo(path, prefs):
|
def _get_svk_repo(path, prefs):
|
||||||
name = path
|
name = path
|
||||||
# parse the ~/.svk/config file to discover which directories are part of
|
# parse the ~/.svk/config file to discover which directories are part of
|
||||||
|
|
|
@ -21,18 +21,17 @@ import difflib
|
||||||
import os
|
import os
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
from diffuse import utils
|
||||||
|
from diffuse.resources import theResources
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('GObject', '2.0')
|
gi.require_version('GObject', '2.0')
|
||||||
gi.require_version('Gdk', '3.0')
|
gi.require_version('Gdk', '3.0')
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
gi.require_version('Pango', '1.0')
|
gi.require_version('Pango', '1.0')
|
||||||
gi.require_version('PangoCairo', '1.0')
|
gi.require_version('PangoCairo', '1.0')
|
||||||
from gi.repository import GObject, Gdk, Gtk, Pango, PangoCairo
|
from gi.repository import GObject, Gdk, Gtk, Pango, PangoCairo # noqa: E402
|
||||||
# pylint: enable=wrong-import-position
|
|
||||||
|
|
||||||
from diffuse import utils
|
|
||||||
from diffuse.resources import theResources
|
|
||||||
|
|
||||||
# mapping to column width of a character (tab will never be in this map)
|
# mapping to column width of a character (tab will never be in this map)
|
||||||
_char_width_cache = {}
|
_char_width_cache = {}
|
||||||
|
@ -43,6 +42,7 @@ LINE_MODE = 0
|
||||||
CHAR_MODE = 1
|
CHAR_MODE = 1
|
||||||
ALIGN_MODE = 2
|
ALIGN_MODE = 2
|
||||||
|
|
||||||
|
|
||||||
# This is a replacement for Gtk.ScrolledWindow as it forced expose events to be
|
# This is a replacement for Gtk.ScrolledWindow as it forced expose events to be
|
||||||
# handled immediately after changing the viewport position. This could cause
|
# handled immediately after changing the viewport position. This could cause
|
||||||
# the application to become unresponsive for a while as it processed a large
|
# the application to become unresponsive for a while as it processed a large
|
||||||
|
@ -140,9 +140,9 @@ class ScrolledWindow(Gtk.Grid):
|
||||||
self.partial_redraw = True
|
self.partial_redraw = True
|
||||||
self.darea_queue_draw_area(x, y, w, h)
|
self.darea_queue_draw_area(x, y, w, h)
|
||||||
|
|
||||||
|
|
||||||
# widget used to compare and merge text files
|
# widget used to compare and merge text files
|
||||||
class FileDiffViewer(Gtk.Grid):
|
class FileDiffViewer(Gtk.Grid):
|
||||||
# pylint: disable=too-many-public-methods
|
|
||||||
# class describing a text pane
|
# class describing a text pane
|
||||||
class Pane:
|
class Pane:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -169,7 +169,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
|
|
||||||
# class describing a single line of a pane
|
# class describing a single line of a pane
|
||||||
class Line:
|
class Line:
|
||||||
def __init__(self, line_number = None, text = None):
|
def __init__(self, line_number=None, text=None):
|
||||||
# line number
|
# line number
|
||||||
self.line_number = line_number
|
self.line_number = line_number
|
||||||
# original text for the line
|
# original text for the line
|
||||||
|
@ -254,7 +254,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
'copy_left_into_selection': self.copy_left_into_selection,
|
'copy_left_into_selection': self.copy_left_into_selection,
|
||||||
'copy_right_into_selection': self.copy_right_into_selection,
|
'copy_right_into_selection': self.copy_right_into_selection,
|
||||||
'merge_from_left_then_right': self.merge_from_left_then_right,
|
'merge_from_left_then_right': self.merge_from_left_then_right,
|
||||||
'merge_from_right_then_left': self.merge_from_right_then_left }
|
'merge_from_right_then_left': self.merge_from_right_then_left
|
||||||
|
}
|
||||||
self._align_mode_actions = {
|
self._align_mode_actions = {
|
||||||
'enter_line_mode': self._align_mode_enter_line_mode,
|
'enter_line_mode': self._align_mode_enter_line_mode,
|
||||||
'enter_character_mode': self.setCharMode,
|
'enter_character_mode': self.setCharMode,
|
||||||
|
@ -266,9 +267,11 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
'right': self._line_mode_right,
|
'right': self._line_mode_right,
|
||||||
'page_up': self._line_mode_page_up,
|
'page_up': self._line_mode_page_up,
|
||||||
'page_down': self._line_mode_page_down,
|
'page_down': self._line_mode_page_down,
|
||||||
'align': self._align_text }
|
'align': self._align_text
|
||||||
|
}
|
||||||
self._character_mode_actions = {
|
self._character_mode_actions = {
|
||||||
'enter_line_mode': self.setLineMode }
|
'enter_line_mode': self.setLineMode
|
||||||
|
}
|
||||||
self._button_actions = {
|
self._button_actions = {
|
||||||
'undo': self.undo,
|
'undo': self.undo,
|
||||||
'redo': self.redo,
|
'redo': self.redo,
|
||||||
|
@ -303,7 +306,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
'copy_left_into_selection': self.copy_left_into_selection,
|
'copy_left_into_selection': self.copy_left_into_selection,
|
||||||
'copy_right_into_selection': self.copy_right_into_selection,
|
'copy_right_into_selection': self.copy_right_into_selection,
|
||||||
'merge_from_left_then_right': self.merge_from_left_then_right,
|
'merge_from_left_then_right': self.merge_from_left_then_right,
|
||||||
'merge_from_right_then_left': self.merge_from_right_then_left }
|
'merge_from_right_then_left': self.merge_from_right_then_left
|
||||||
|
}
|
||||||
|
|
||||||
# create panes
|
# create panes
|
||||||
self.dareas = []
|
self.dareas = []
|
||||||
|
@ -334,8 +338,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# add diff map
|
# add diff map
|
||||||
self.diffmap = diffmap = Gtk.DrawingArea.new()
|
self.diffmap = diffmap = Gtk.DrawingArea.new()
|
||||||
diffmap.add_events(Gdk.EventMask.BUTTON_PRESS_MASK |
|
diffmap.add_events(Gdk.EventMask.BUTTON_PRESS_MASK |
|
||||||
Gdk.EventMask.BUTTON1_MOTION_MASK |
|
Gdk.EventMask.BUTTON1_MOTION_MASK |
|
||||||
Gdk.EventMask.SCROLL_MASK)
|
Gdk.EventMask.SCROLL_MASK)
|
||||||
diffmap.connect('button-press-event', self.diffmap_button_press_cb)
|
diffmap.connect('button-press-event', self.diffmap_button_press_cb)
|
||||||
diffmap.connect('motion-notify-event', self.diffmap_button_press_cb)
|
diffmap.connect('motion-notify-event', self.diffmap_button_press_cb)
|
||||||
diffmap.connect('scroll-event', self.diffmap_scroll_cb)
|
diffmap.connect('scroll-event', self.diffmap_scroll_cb)
|
||||||
|
@ -343,7 +347,6 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
self.attach(diffmap, n, 1, 1, 1)
|
self.attach(diffmap, n, 1, 1, 1)
|
||||||
diffmap.show()
|
diffmap.show()
|
||||||
diffmap.set_size_request(16 * n, 0)
|
diffmap.set_size_request(16 * n, 0)
|
||||||
# pylint: disable-next=no-member
|
|
||||||
self.add_events(Gdk.EventMask.KEY_PRESS_MASK |
|
self.add_events(Gdk.EventMask.KEY_PRESS_MASK |
|
||||||
Gdk.EventMask.FOCUS_CHANGE_MASK)
|
Gdk.EventMask.FOCUS_CHANGE_MASK)
|
||||||
self.connect('focus-in-event', self.focus_in_cb)
|
self.connect('focus-in-event', self.focus_in_cb)
|
||||||
|
@ -372,7 +375,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# this must be connected with 'connect_after()' so the final widget sizes
|
# this must be connected with 'connect_after()' so the final widget sizes
|
||||||
# are known and the scroll bar can be moved to the first difference
|
# are known and the scroll bar can be moved to the first difference
|
||||||
def _realise_cb(self, widget):
|
def _realise_cb(self, widget):
|
||||||
self.im_context.set_client_window(self.get_window()) # pylint: disable=no-member
|
self.im_context.set_client_window(self.get_window())
|
||||||
try:
|
try:
|
||||||
self.go_to_line(self.options['line'])
|
self.go_to_line(self.options['line'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -635,7 +638,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
if f is None:
|
if f is None:
|
||||||
panes = self.panes
|
panes = self.panes
|
||||||
else:
|
else:
|
||||||
panes = [ self.panes[f] ]
|
panes = [self.panes[f]]
|
||||||
for _, pane in enumerate(panes):
|
for _, pane in enumerate(panes):
|
||||||
del pane.syntax_cache[:]
|
del pane.syntax_cache[:]
|
||||||
del pane.diff_cache[:]
|
del pane.diff_cache[:]
|
||||||
|
@ -644,7 +647,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
for line in pane.lines:
|
for line in pane.lines:
|
||||||
if line is not None:
|
if line is not None:
|
||||||
line.compare_string = None
|
line.compare_string = None
|
||||||
text = [ line.text ]
|
text = [line.text]
|
||||||
if line.is_modified:
|
if line.is_modified:
|
||||||
text.append(line.modified_text)
|
text.append(line.modified_text)
|
||||||
for s in text:
|
for s in text:
|
||||||
|
@ -869,7 +872,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
for f, pane in enumerate(self.panes):
|
for f, pane in enumerate(self.panes):
|
||||||
if i < len(pane.diff_cache):
|
if i < len(pane.diff_cache):
|
||||||
if i2 + 1 < len(pane.diff_cache):
|
if i2 + 1 < len(pane.diff_cache):
|
||||||
pane.diff_cache[i:i2] = new_n * [ None ]
|
pane.diff_cache[i:i2] = new_n * [None]
|
||||||
else:
|
else:
|
||||||
del pane.diff_cache[i:]
|
del pane.diff_cache[i:]
|
||||||
self.dareas[f].queue_draw()
|
self.dareas[f].queue_draw()
|
||||||
|
@ -942,7 +945,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# insert 'n' blank lines in all panes
|
# insert 'n' blank lines in all panes
|
||||||
def insertLines(self, i, n):
|
def insertLines(self, i, n):
|
||||||
# insert lines
|
# insert lines
|
||||||
self.updateAlignment(i, 0, [ n * [ None ] for pane in self.panes ])
|
self.updateAlignment(i, 0, [n * [None] for pane in self.panes])
|
||||||
pre, post = _cut_blocks(i, self.blocks)
|
pre, post = _cut_blocks(i, self.blocks)
|
||||||
pre.append(n)
|
pre.append(n)
|
||||||
pre.extend(post)
|
pre.extend(post)
|
||||||
|
@ -1092,19 +1095,19 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# needed for alignment are inserted in all lists of lines for a particular
|
# needed for alignment are inserted in all lists of lines for a particular
|
||||||
# side to keep them all in sync.
|
# side to keep them all in sync.
|
||||||
def alignBlocks(self, leftblocks, leftlines, rightblocks, rightlines):
|
def alignBlocks(self, leftblocks, leftlines, rightblocks, rightlines):
|
||||||
blocks = ( leftblocks, rightblocks )
|
blocks = (leftblocks, rightblocks)
|
||||||
lines = ( leftlines, rightlines )
|
lines = (leftlines, rightlines)
|
||||||
# get the inner lines we are to match
|
# get the inner lines we are to match
|
||||||
middle = ( leftlines[-1], rightlines[0] )
|
middle = (leftlines[-1], rightlines[0])
|
||||||
# eliminate any existing spacer lines
|
# eliminate any existing spacer lines
|
||||||
mlines = ( [ line for line in middle[0] if line is not None ],
|
mlines = ([line for line in middle[0] if line is not None],
|
||||||
[ line for line in middle[1] if line is not None ] )
|
[line for line in middle[1] if line is not None])
|
||||||
s1, s2 = mlines
|
s1, s2 = mlines
|
||||||
n1, n2 = 0, 0
|
n1, n2 = 0, 0
|
||||||
# hash lines according to the alignment preferences
|
# hash lines according to the alignment preferences
|
||||||
a = self._alignmentHash
|
a = self._alignmentHash
|
||||||
t1 = [ a(s) for s in s1 ]
|
t1 = [a(s) for s in s1]
|
||||||
t2 = [ a(s) for s in s2 ]
|
t2 = [a(s) for s in s2]
|
||||||
# align s1 and s2 by inserting spacer lines
|
# align s1 and s2 by inserting spacer lines
|
||||||
# this will be used to determine which lines from the inner lists of
|
# this will be used to determine which lines from the inner lists of
|
||||||
# lines should be neighbours
|
# lines should be neighbours
|
||||||
|
@ -1113,12 +1116,12 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
if delta < 0:
|
if delta < 0:
|
||||||
# insert spacer lines in s1
|
# insert spacer lines in s1
|
||||||
i = n1 + block[0]
|
i = n1 + block[0]
|
||||||
s1[i:i] = -delta * [ None ]
|
s1[i:i] = -delta * [None]
|
||||||
n1 -= delta
|
n1 -= delta
|
||||||
elif delta > 0:
|
elif delta > 0:
|
||||||
# insert spacer lines in s2
|
# insert spacer lines in s2
|
||||||
i = n2 + block[1]
|
i = n2 + block[1]
|
||||||
s2[i:i] = delta * [ None ]
|
s2[i:i] = delta * [None]
|
||||||
n2 += delta
|
n2 += delta
|
||||||
nmatch = len(s1)
|
nmatch = len(s1)
|
||||||
|
|
||||||
|
@ -1128,19 +1131,19 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
#
|
#
|
||||||
# advance one row at a time inserting spacer lines as we go
|
# advance one row at a time inserting spacer lines as we go
|
||||||
# 'i' indicates which row we are processing
|
# 'i' indicates which row we are processing
|
||||||
# 'k' indicates which pair of neighbours we are processing
|
# 'k' indicates which pair of neighbors we are processing
|
||||||
i, k = 0, 0
|
i, k = 0, 0
|
||||||
bi = [ 0, 0 ]
|
bi = [0, 0]
|
||||||
bn = [ 0, 0 ]
|
bn = [0, 0]
|
||||||
while True:
|
while True:
|
||||||
# if we have reached the end of the list for any side, it needs
|
# if we have reached the end of the list for any side, it needs
|
||||||
# spacer lines to align with the other side
|
# spacer lines to align with the other side
|
||||||
insert = [ i >= len(m) for m in middle ]
|
insert = [i >= len(m) for m in middle]
|
||||||
if insert == [ True, True ]:
|
if insert == [True, True]:
|
||||||
# we have reached the end of both inner lists of lines
|
# we have reached the end of both inner lists of lines
|
||||||
# we are done
|
# we are done
|
||||||
break
|
break
|
||||||
if insert == [ False, False ] and k < nmatch:
|
if insert == [False, False] and k < nmatch:
|
||||||
# determine if either side needs spacer lines to make the
|
# determine if either side needs spacer lines to make the
|
||||||
# inner list of lines match up
|
# inner list of lines match up
|
||||||
accept = True
|
accept = True
|
||||||
|
@ -1162,7 +1165,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
k += 1
|
k += 1
|
||||||
else:
|
else:
|
||||||
# insert spacer lines as needed
|
# insert spacer lines as needed
|
||||||
insert = [ m[i] is not None for m in middle ]
|
insert = [m[i] is not None for m in middle]
|
||||||
for j in range(2):
|
for j in range(2):
|
||||||
if insert[j]:
|
if insert[j]:
|
||||||
# insert spacers lines for side 'j'
|
# insert spacers lines for side 'j'
|
||||||
|
@ -1196,13 +1199,13 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
blocks.append(n)
|
blocks.append(n)
|
||||||
# create line objects for the text
|
# create line objects for the text
|
||||||
Line = FileDiffViewer.Line
|
Line = FileDiffViewer.Line
|
||||||
mid = [ [ Line(j + 1, ss[j]) for j in range(n) ] ]
|
mid = [[Line(j + 1, ss[j]) for j in range(n)]]
|
||||||
|
|
||||||
if f > 0:
|
if f > 0:
|
||||||
# align with panes to the left
|
# align with panes to the left
|
||||||
# use copies so the originals can be used by the Undo object
|
# use copies so the originals can be used by the Undo object
|
||||||
leftblocks = self.blocks[:]
|
leftblocks = self.blocks[:]
|
||||||
leftlines = [ pane.lines[:] for pane in self.panes[:f] ]
|
leftlines = [pane.lines[:] for pane in self.panes[:f]]
|
||||||
_remove_null_lines(leftblocks, leftlines)
|
_remove_null_lines(leftblocks, leftlines)
|
||||||
self.alignBlocks(leftblocks, leftlines, blocks, mid)
|
self.alignBlocks(leftblocks, leftlines, blocks, mid)
|
||||||
mid[:0] = leftlines
|
mid[:0] = leftlines
|
||||||
|
@ -1211,7 +1214,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# align with panes to the right
|
# align with panes to the right
|
||||||
# use copies so the originals can be used by the Undo object
|
# use copies so the originals can be used by the Undo object
|
||||||
rightblocks = self.blocks[:]
|
rightblocks = self.blocks[:]
|
||||||
rightlines = [ pane.lines[:] for pane in self.panes[f + 1:] ]
|
rightlines = [pane.lines[:] for pane in self.panes[f + 1:]]
|
||||||
_remove_null_lines(rightblocks, rightlines)
|
_remove_null_lines(rightblocks, rightlines)
|
||||||
self.alignBlocks(blocks, mid, rightblocks, rightlines)
|
self.alignBlocks(blocks, mid, rightblocks, rightlines)
|
||||||
mid.extend(rightlines)
|
mid.extend(rightlines)
|
||||||
|
@ -1295,7 +1298,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# change the format to that of the target pane
|
# change the format to that of the target pane
|
||||||
if pane.format == 0:
|
if pane.format == 0:
|
||||||
self.setFormat(f, _get_format(ss))
|
self.setFormat(f, _get_format(ss))
|
||||||
ss = [ _convert_to_format(s, pane.format) for s in ss ]
|
ss = [_convert_to_format(s, pane.format) for s in ss]
|
||||||
# prepend original text that was before the selection
|
# prepend original text that was before the selection
|
||||||
if col0 > 0:
|
if col0 > 0:
|
||||||
pre = self.getLineText(f, line0)[:col0]
|
pre = self.getLineText(f, line0)[:col0]
|
||||||
|
@ -1379,11 +1382,11 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# 2. the matched pair
|
# 2. the matched pair
|
||||||
# 3. lines after the matched pair
|
# 3. lines after the matched pair
|
||||||
# each section has lines and blocks for left and right sides
|
# each section has lines and blocks for left and right sides
|
||||||
lines_s = [ [], [], [] ]
|
lines_s = [[], [], []]
|
||||||
cutblocks = [ [], [], [] ]
|
cutblocks = [[], [], []]
|
||||||
lines = [ pane.lines for pane in self.panes ]
|
lines = [pane.lines for pane in self.panes]
|
||||||
nlines = len(lines[0])
|
nlines = len(lines[0])
|
||||||
for temp, m in zip([ lines[:f + 1], lines[f + 1:] ], [ line1, line2 ]):
|
for temp, m in zip([lines[:f + 1], lines[f + 1:]], [line1, line2]):
|
||||||
# cut the blocks just before the line being matched
|
# cut the blocks just before the line being matched
|
||||||
pre, post = _cut_blocks(m - start, mid)
|
pre, post = _cut_blocks(m - start, mid)
|
||||||
if len(temp) == 1:
|
if len(temp) == 1:
|
||||||
|
@ -1391,12 +1394,12 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# preserve other cuts
|
# preserve other cuts
|
||||||
pre = _create_block(sum(pre))
|
pre = _create_block(sum(pre))
|
||||||
# the first section of lines to match
|
# the first section of lines to match
|
||||||
lines_s[0].append([ s[start:m] for s in temp ])
|
lines_s[0].append([s[start:m] for s in temp])
|
||||||
cutblocks[0].append(pre)
|
cutblocks[0].append(pre)
|
||||||
# the line to match may be after the actual lines
|
# the line to match may be after the actual lines
|
||||||
if m < nlines:
|
if m < nlines:
|
||||||
m1 = [ [ s[m] ] for s in temp ]
|
m1 = [[s[m]] for s in temp]
|
||||||
m2 = [ s[m + 1:end] for s in temp ]
|
m2 = [s[m + 1:end] for s in temp]
|
||||||
# cut the blocks just after the line being matched
|
# cut the blocks just after the line being matched
|
||||||
b1, b2 = _cut_blocks(1, post)
|
b1, b2 = _cut_blocks(1, post)
|
||||||
if len(temp) == 1:
|
if len(temp) == 1:
|
||||||
|
@ -1404,8 +1407,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# preserve other cuts
|
# preserve other cuts
|
||||||
b2 = _create_block(sum(b2))
|
b2 = _create_block(sum(b2))
|
||||||
else:
|
else:
|
||||||
m1 = [ [] for s in temp ]
|
m1 = [[] for s in temp]
|
||||||
m2 = [ [] for s in temp ]
|
m2 = [[] for s in temp]
|
||||||
b1, b2 = [], []
|
b1, b2 = [], []
|
||||||
# the second section of lines to match
|
# the second section of lines to match
|
||||||
lines_s[1].append(m1)
|
lines_s[1].append(m1)
|
||||||
|
@ -1415,7 +1418,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
cutblocks[2].append(b2)
|
cutblocks[2].append(b2)
|
||||||
|
|
||||||
# align each section and concatenate the results
|
# align each section and concatenate the results
|
||||||
finallines = [ [] for s in lines ]
|
finallines = [[] for s in lines]
|
||||||
for b, lines_t in zip(cutblocks, lines_s):
|
for b, lines_t in zip(cutblocks, lines_s):
|
||||||
_remove_null_lines(b[0], lines_t[0])
|
_remove_null_lines(b[0], lines_t[0])
|
||||||
_remove_null_lines(b[1], lines_t[1])
|
_remove_null_lines(b[1], lines_t[1])
|
||||||
|
@ -1606,7 +1609,6 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
x -= int(self.hadj.get_value())
|
x -= int(self.hadj.get_value())
|
||||||
y -= int(self.vadj.get_value())
|
y -= int(self.vadj.get_value())
|
||||||
# translate to a position relative to the window
|
# translate to a position relative to the window
|
||||||
# pylint: disable=no-member
|
|
||||||
x, y = self.dareas[self.current_pane].translate_coordinates(self.get_toplevel(), x, y)
|
x, y = self.dareas[self.current_pane].translate_coordinates(self.get_toplevel(), x, y)
|
||||||
# input methods support widgets are centred horizontally about the
|
# input methods support widgets are centred horizontally about the
|
||||||
# cursor, a width of 50 seems to give a better widget positions
|
# cursor, a width of 50 seems to give a better widget positions
|
||||||
|
@ -1705,14 +1707,14 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
end += 1
|
end += 1
|
||||||
# get the text for the selected lines
|
# get the text for the selected lines
|
||||||
end = min(end, len(self.panes[f].lines))
|
end = min(end, len(self.panes[f].lines))
|
||||||
ss = [ self.getLineText(f, i) for i in range(start, end) ]
|
ss = [self.getLineText(f, i) for i in range(start, end)]
|
||||||
# trim out the unselected parts of the lines
|
# trim out the unselected parts of the lines
|
||||||
# check for col > 0 as some lines may be null
|
# check for col > 0 as some lines may be null
|
||||||
if col1 > 0:
|
if col1 > 0:
|
||||||
ss[-1] = ss[-1][:col1]
|
ss[-1] = ss[-1][:col1]
|
||||||
if col0 > 0:
|
if col0 > 0:
|
||||||
ss[0] = ss[0][col0:]
|
ss[0] = ss[0][col0:]
|
||||||
return ''.join([ s for s in ss if s is not None ])
|
return ''.join([s for s in ss if s is not None])
|
||||||
|
|
||||||
# expands the selection to include everything
|
# expands the selection to include everything
|
||||||
def select_all(self):
|
def select_all(self):
|
||||||
|
@ -1771,14 +1773,14 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
|
|
||||||
# callback for mouse button presses in the text window
|
# callback for mouse button presses in the text window
|
||||||
def darea_button_press_cb(self, widget, event, f):
|
def darea_button_press_cb(self, widget, event, f):
|
||||||
self.get_toplevel().set_focus(self) # pylint: disable=no-member
|
self.get_toplevel().set_focus(self)
|
||||||
x = int(event.x + self.hadj.get_value())
|
x = int(event.x + self.hadj.get_value())
|
||||||
y = int(event.y + self.vadj.get_value())
|
y = int(event.y + self.vadj.get_value())
|
||||||
nlines = len(self.panes[f].lines)
|
nlines = len(self.panes[f].lines)
|
||||||
i = min(y // self.font_height, nlines)
|
i = min(y // self.font_height, nlines)
|
||||||
if event.button == 1:
|
if event.button == 1:
|
||||||
# left mouse button
|
# left mouse button
|
||||||
if event.type == Gdk.EventType._2BUTTON_PRESS: # pylint: disable=no-member,protected-access
|
if event.type == Gdk.EventType._2BUTTON_PRESS:
|
||||||
# double click
|
# double click
|
||||||
if self.mode == ALIGN_MODE:
|
if self.mode == ALIGN_MODE:
|
||||||
self.setLineMode()
|
self.setLineMode()
|
||||||
|
@ -1804,7 +1806,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
while j < n and _get_character_class(text[j]) == c:
|
while j < n and _get_character_class(text[j]) == c:
|
||||||
j += 1
|
j += 1
|
||||||
self.setCurrentChar(i, j, i, k)
|
self.setCurrentChar(i, j, i, k)
|
||||||
elif event.type == Gdk.EventType._3BUTTON_PRESS: # pylint: disable=no-member,protected-access
|
elif event.type == Gdk.EventType._3BUTTON_PRESS:
|
||||||
# triple click, select a whole line
|
# triple click, select a whole line
|
||||||
if self.mode == CHAR_MODE and self.current_pane == f:
|
if self.mode == CHAR_MODE and self.current_pane == f:
|
||||||
i2 = min(i + 1, nlines)
|
i2 = min(i + 1, nlines)
|
||||||
|
@ -1833,21 +1835,20 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
can_select = self.mode in (LINE_MODE, CHAR_MODE) and f == self.current_pane
|
can_select = self.mode in (LINE_MODE, CHAR_MODE) and f == self.current_pane
|
||||||
can_swap = (f != self.current_pane)
|
can_swap = (f != self.current_pane)
|
||||||
|
|
||||||
# pylint: disable=line-too-long
|
menu = createMenu([
|
||||||
menu = createMenu(
|
[_('Align with Selection'), self.align_with_selection_cb, [f, i], Gtk.STOCK_EXECUTE, None, can_align], # noqa: E501
|
||||||
[ [_('Align with Selection'), self.align_with_selection_cb, [f, i], Gtk.STOCK_EXECUTE, None, can_align],
|
[_('Isolate'), self.button_cb, 'isolate', None, None, can_isolate],
|
||||||
[_('Isolate'), self.button_cb, 'isolate', None, None, can_isolate ],
|
[_('Merge Selection'), self.merge_lines_cb, f, None, None, can_merge],
|
||||||
[_('Merge Selection'), self.merge_lines_cb, f, None, None, can_merge],
|
[],
|
||||||
[],
|
[_('Cut'), self.button_cb, 'cut', Gtk.STOCK_CUT, None, can_select],
|
||||||
[_('Cut'), self.button_cb, 'cut', Gtk.STOCK_CUT, None, can_select],
|
[_('Copy'), self.button_cb, 'copy', Gtk.STOCK_COPY, None, can_select],
|
||||||
[_('Copy'), self.button_cb, 'copy', Gtk.STOCK_COPY, None, can_select],
|
[_('Paste'), self.button_cb, 'paste', Gtk.STOCK_PASTE, None, can_select],
|
||||||
[_('Paste'), self.button_cb, 'paste', Gtk.STOCK_PASTE, None, can_select],
|
[],
|
||||||
[],
|
[_('Select All'), self.button_cb, 'select_all', None, None, can_select],
|
||||||
[_('Select All'), self.button_cb, 'select_all', None, None, can_select],
|
[_('Clear Edits'), self.button_cb, 'clear_edits', Gtk.STOCK_CLEAR, None, can_isolate], # noqa: E501
|
||||||
[_('Clear Edits'), self.button_cb, 'clear_edits', Gtk.STOCK_CLEAR, None, can_isolate],
|
[],
|
||||||
[],
|
[_('Swap with Selected Pane'), self.swap_panes_cb, f, None, None, can_swap]
|
||||||
[_('Swap with Selected Pane'), self.swap_panes_cb, f, None, None, can_swap] ])
|
])
|
||||||
# pylint: enable=line-too-long
|
|
||||||
menu.attach_to_widget(self)
|
menu.attach_to_widget(self)
|
||||||
menu.popup(None, None, None, None, event.button, event.time)
|
menu.popup(None, None, None, None, event.button, event.time)
|
||||||
|
|
||||||
|
@ -1996,7 +1997,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
|
|
||||||
diffcolours = [
|
diffcolours = [
|
||||||
theResources.getDifferenceColour(f),
|
theResources.getDifferenceColour(f),
|
||||||
theResources.getDifferenceColour(f + 1) ]
|
theResources.getDifferenceColour(f + 1)
|
||||||
|
]
|
||||||
diffcolours.append((diffcolours[0] + diffcolours[1]) * 0.5)
|
diffcolours.append((diffcolours[0] + diffcolours[1]) * 0.5)
|
||||||
|
|
||||||
# iterate over each exposed line
|
# iterate over each exposed line
|
||||||
|
@ -2036,7 +2038,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
|
|
||||||
# enlarge cache to fit pan.diff_cache[i]
|
# enlarge cache to fit pan.diff_cache[i]
|
||||||
if i >= len(pane.diff_cache):
|
if i >= len(pane.diff_cache):
|
||||||
pane.diff_cache.extend((i - len(pane.diff_cache) + 1) * [ None ])
|
pane.diff_cache.extend((i - len(pane.diff_cache) + 1) * [None])
|
||||||
# construct a list of ranges for this lines character
|
# construct a list of ranges for this lines character
|
||||||
# differences if not already cached
|
# differences if not already cached
|
||||||
if pane.diff_cache[i] is None:
|
if pane.diff_cache[i] is None:
|
||||||
|
@ -2198,7 +2200,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
if temp < x:
|
if temp < x:
|
||||||
temp += ((x - temp) // h) * h
|
temp += ((x - temp) // h) * h
|
||||||
h_half = 0.5 * h
|
h_half = 0.5 * h
|
||||||
phase = [ h_half, h_half, -h_half, -h_half ]
|
phase = [h_half, h_half, -h_half, -h_half]
|
||||||
for j in range(4):
|
for j in range(4):
|
||||||
x_temp = temp
|
x_temp = temp
|
||||||
y_temp = y_start
|
y_temp = y_start
|
||||||
|
@ -2224,7 +2226,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
if temp is None:
|
if temp is None:
|
||||||
blocks = None
|
blocks = None
|
||||||
else:
|
else:
|
||||||
blocks = [ (0, len(temp), 'text') ]
|
blocks = [(0, len(temp), 'text')]
|
||||||
else:
|
else:
|
||||||
# apply the syntax highlighting rules to identify
|
# apply the syntax highlighting rules to identify
|
||||||
# ranges of similarly coloured characters
|
# ranges of similarly coloured characters
|
||||||
|
@ -2364,9 +2366,9 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# flags & 8 indicates regular lines with text
|
# flags & 8 indicates regular lines with text
|
||||||
if self.diffmap_cache is None:
|
if self.diffmap_cache is None:
|
||||||
nlines = len(self.panes[0].lines)
|
nlines = len(self.panes[0].lines)
|
||||||
start = n * [ 0 ]
|
start = n * [0]
|
||||||
flags = n * [ 0 ]
|
flags = n * [0]
|
||||||
self.diffmap_cache = [ [] for f in range(n) ]
|
self.diffmap_cache = [[] for f in range(n)]
|
||||||
# iterate over each row of lines
|
# iterate over each row of lines
|
||||||
for i in range(nlines):
|
for i in range(nlines):
|
||||||
nextflag = 0
|
nextflag = 0
|
||||||
|
@ -2419,7 +2421,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
for f in range(n):
|
for f in range(n):
|
||||||
diffcolours = [
|
diffcolours = [
|
||||||
theResources.getDifferenceColour(f),
|
theResources.getDifferenceColour(f),
|
||||||
theResources.getDifferenceColour(f + 1) ]
|
theResources.getDifferenceColour(f + 1)
|
||||||
|
]
|
||||||
diffcolours.append((diffcolours[0] + diffcolours[1]) * 0.5)
|
diffcolours.append((diffcolours[0] + diffcolours[1]) * 0.5)
|
||||||
wx = f * wn
|
wx = f * wn
|
||||||
# draw in two passes, more important stuff in the second pass
|
# draw in two passes, more important stuff in the second pass
|
||||||
|
@ -2443,8 +2446,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
break
|
break
|
||||||
yh = max(rect.height * self.font_height * end // hmax - ymin, 1)
|
yh = max(rect.height * self.font_height * end // hmax - ymin, 1)
|
||||||
|
|
||||||
#if ymin + yh <= rect.y:
|
# if ymin + yh <= rect.y:
|
||||||
# continue
|
# continue
|
||||||
|
|
||||||
cr.set_source_rgb(colour.red, colour.green, colour.blue)
|
cr.set_source_rgb(colour.red, colour.green, colour.blue)
|
||||||
cr.rectangle(wx + pad, ymin, wn - 2 * pad, yh)
|
cr.rectangle(wx + pad, ymin, wn - 2 * pad, yh)
|
||||||
|
@ -2458,7 +2461,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
yh = rect.height * vmax // hmax - ymin
|
yh = rect.height * vmax // hmax - ymin
|
||||||
if yh > 1:
|
if yh > 1:
|
||||||
yh -= 1
|
yh -= 1
|
||||||
#if ymin + yh > rect.y:
|
# if ymin + yh > rect.y:
|
||||||
colour = theResources.getColour('line_selection')
|
colour = theResources.getColour('line_selection')
|
||||||
alpha = theResources.getFloat('line_selection_opacity')
|
alpha = theResources.getFloat('line_selection_opacity')
|
||||||
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
|
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
|
||||||
|
@ -2675,7 +2678,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
elif event.keyval == Gdk.KEY_Tab and event.state & Gdk.ModifierType.CONTROL_MASK:
|
elif event.keyval == Gdk.KEY_Tab and event.state & Gdk.ModifierType.CONTROL_MASK:
|
||||||
retval = False
|
retval = False
|
||||||
# up/down cursor navigation
|
# up/down cursor navigation
|
||||||
elif event.keyval in [ Gdk.KEY_Up, Gdk.KEY_Down, Gdk.KEY_Page_Up, Gdk.KEY_Page_Down ]:
|
elif event.keyval in [Gdk.KEY_Up, Gdk.KEY_Down, Gdk.KEY_Page_Up, Gdk.KEY_Page_Down]:
|
||||||
i = self.current_line
|
i = self.current_line
|
||||||
# move back to the remembered cursor column if possible
|
# move back to the remembered cursor column if possible
|
||||||
col = self.cursor_column
|
col = self.cursor_column
|
||||||
|
@ -2683,11 +2686,11 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# find the current cursor column
|
# find the current cursor column
|
||||||
s = utils.null_to_empty(self.getLineText(f, i))[:self.current_char]
|
s = utils.null_to_empty(self.getLineText(f, i))[:self.current_char]
|
||||||
col = self.stringWidth(s)
|
col = self.stringWidth(s)
|
||||||
if event.keyval in [ Gdk.KEY_Up, Gdk.KEY_Down ]:
|
if event.keyval in [Gdk.KEY_Up, Gdk.KEY_Down]:
|
||||||
delta = 1
|
delta = 1
|
||||||
else:
|
else:
|
||||||
delta = int(self.vadj.get_page_size() // self.font_height)
|
delta = int(self.vadj.get_page_size() // self.font_height)
|
||||||
if event.keyval in [ Gdk.KEY_Up, Gdk.KEY_Page_Up ]:
|
if event.keyval in [Gdk.KEY_Up, Gdk.KEY_Page_Up]:
|
||||||
delta = -delta
|
delta = -delta
|
||||||
i += delta
|
i += delta
|
||||||
j = 0
|
j = 0
|
||||||
|
@ -2818,7 +2821,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
self.current_char = j
|
self.current_char = j
|
||||||
self.replaceText('')
|
self.replaceText('')
|
||||||
# return key, add the platform specific end of line characters
|
# return key, add the platform specific end of line characters
|
||||||
elif event.keyval in [ Gdk.KEY_Return, Gdk.KEY_KP_Enter ]:
|
elif event.keyval in [Gdk.KEY_Return, Gdk.KEY_KP_Enter]:
|
||||||
s = os.linesep
|
s = os.linesep
|
||||||
if self.prefs.getBool('editor_auto_indent'):
|
if self.prefs.getBool('editor_auto_indent'):
|
||||||
start_i, start_j = self.selection_line, self.selection_char
|
start_i, start_j = self.selection_line, self.selection_char
|
||||||
|
@ -2840,7 +2843,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
s += ' ' * (w % tab_width)
|
s += ' ' * (w % tab_width)
|
||||||
self.replaceText(s)
|
self.replaceText(s)
|
||||||
# insert key
|
# insert key
|
||||||
elif event.keyval in [ Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab ]:
|
elif event.keyval in [Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab]:
|
||||||
start_i, start_j = self.selection_line, self.selection_char
|
start_i, start_j = self.selection_line, self.selection_char
|
||||||
end_i, end_j = self.current_line, self.current_char
|
end_i, end_j = self.current_line, self.current_char
|
||||||
if start_i != end_i or start_j != end_j or event.keyval == Gdk.KEY_ISO_Left_Tab:
|
if start_i != end_i or start_j != end_j or event.keyval == Gdk.KEY_ISO_Left_Tab:
|
||||||
|
@ -3075,7 +3078,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
blocks = []
|
blocks = []
|
||||||
for pane in self.panes:
|
for pane in self.panes:
|
||||||
# create a new list of lines with no spacers
|
# create a new list of lines with no spacers
|
||||||
newlines = [ [ line for line in pane.lines if line is not None ] ]
|
newlines = [[line for line in pane.lines if line is not None]]
|
||||||
newblocks = _create_block(len(newlines[0]))
|
newblocks = _create_block(len(newlines[0]))
|
||||||
if len(lines) > 0:
|
if len(lines) > 0:
|
||||||
# match with neighbour to the left
|
# match with neighbour to the left
|
||||||
|
@ -3118,8 +3121,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
end = min(end, nlines)
|
end = min(end, nlines)
|
||||||
n = end - start
|
n = end - start
|
||||||
if n > 0:
|
if n > 0:
|
||||||
lines = [ pane.lines[start:end] for pane in self.panes ]
|
lines = [pane.lines[start:end] for pane in self.panes]
|
||||||
space = [ n * [ None ] for pane in self.panes ]
|
space = [n * [None] for pane in self.panes]
|
||||||
lines[f], space[f] = space[f], lines[f]
|
lines[f], space[f] = space[f], lines[f]
|
||||||
|
|
||||||
pre, post = _cut_blocks(end, self.blocks)
|
pre, post = _cut_blocks(end, self.blocks)
|
||||||
|
@ -3343,14 +3346,14 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
if end < start:
|
if end < start:
|
||||||
start, end = end, start
|
start, end = end, start
|
||||||
# get set of lines
|
# get set of lines
|
||||||
ss = [ self.getLineText(f, i) for i in range(start, end + 1) ]
|
ss = [self.getLineText(f, i) for i in range(start, end + 1)]
|
||||||
# create sorted list, removing any nulls
|
# create sorted list, removing any nulls
|
||||||
temp = [ s for s in ss if s is not None ]
|
temp = [s for s in ss if s is not None]
|
||||||
temp.sort()
|
temp.sort()
|
||||||
if descending:
|
if descending:
|
||||||
temp.reverse()
|
temp.reverse()
|
||||||
# add back in the nulls
|
# add back in the nulls
|
||||||
temp.extend((len(ss) - len(temp)) * [ None ])
|
temp.extend((len(ss) - len(temp)) * [None])
|
||||||
for i, s in enumerate(temp):
|
for i, s in enumerate(temp):
|
||||||
# update line if it changed
|
# update line if it changed
|
||||||
if ss[i] != s:
|
if ss[i] != s:
|
||||||
|
@ -3468,7 +3471,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
j += 1
|
j += 1
|
||||||
if col >= tab_width:
|
if col >= tab_width:
|
||||||
# convert to tabs
|
# convert to tabs
|
||||||
s = ''.join([ '\t' * (col // tab_width), ' ' * (col % tab_width), text[j:] ])
|
s = ''.join(['\t' * (col // tab_width), ' ' * (col % tab_width), text[j:]])
|
||||||
# update line only if it changed
|
# update line only if it changed
|
||||||
if text != s:
|
if text != s:
|
||||||
self.updateText(f, i, s)
|
self.updateText(f, i, s)
|
||||||
|
@ -3551,7 +3554,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
if end < start:
|
if end < start:
|
||||||
start, end = end, start
|
start, end = end, start
|
||||||
end = min(end + 1, len(pane.lines))
|
end = min(end + 1, len(pane.lines))
|
||||||
ss = [ self.getLineText(f_src, i) for i in range(start, end) ]
|
ss = [self.getLineText(f_src, i) for i in range(start, end)]
|
||||||
if pane.format == 0:
|
if pane.format == 0:
|
||||||
# copy the format of the source pane if the format for the
|
# copy the format of the source pane if the format for the
|
||||||
# destination pane as not yet been determined
|
# destination pane as not yet been determined
|
||||||
|
@ -3610,20 +3613,20 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
end = min(end, nlines)
|
end = min(end, nlines)
|
||||||
n = end - start
|
n = end - start
|
||||||
if n > 0:
|
if n > 0:
|
||||||
lines = [ pane.lines[start:end] for pane in self.panes ]
|
lines = [pane.lines[start:end] for pane in self.panes]
|
||||||
spaces = [ n * [ None ] for pane in self.panes ]
|
spaces = [n * [None] for pane in self.panes]
|
||||||
old_content = [ line for line in lines[f] if line is not None ]
|
old_content = [line for line in lines[f] if line is not None]
|
||||||
for i in range(f + 1, npanes):
|
for i in range(f + 1, npanes):
|
||||||
lines[i], spaces[i] = spaces[i], lines[i]
|
lines[i], spaces[i] = spaces[i], lines[i]
|
||||||
# replace f's lines with merge content
|
# replace f's lines with merge content
|
||||||
if f > 0:
|
if f > 0:
|
||||||
lines[f] = lines[f - 1][:]
|
lines[f] = lines[f - 1][:]
|
||||||
else:
|
else:
|
||||||
lines[f] = n * [ None ]
|
lines[f] = n * [None]
|
||||||
if f + 1 < npanes:
|
if f + 1 < npanes:
|
||||||
spaces[f] = spaces[f + 1][:]
|
spaces[f] = spaces[f + 1][:]
|
||||||
else:
|
else:
|
||||||
spaces[f] = n * [ None ]
|
spaces[f] = n * [None]
|
||||||
if right_first:
|
if right_first:
|
||||||
lines, spaces = spaces, lines
|
lines, spaces = spaces, lines
|
||||||
|
|
||||||
|
@ -3632,8 +3635,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
|
|
||||||
# join and remove null lines
|
# join and remove null lines
|
||||||
b.extend(b)
|
b.extend(b)
|
||||||
for l, s in zip(lines, spaces):
|
for line, space in zip(lines, spaces):
|
||||||
l.extend(s)
|
line.extend(space)
|
||||||
_remove_null_lines(b, lines)
|
_remove_null_lines(b, lines)
|
||||||
|
|
||||||
# replace f's lines with original, growing if necessary
|
# replace f's lines with original, growing if necessary
|
||||||
|
@ -3647,14 +3650,14 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
delta = -delta
|
delta = -delta
|
||||||
for i in range(npanes):
|
for i in range(npanes):
|
||||||
if i != f:
|
if i != f:
|
||||||
lines[i].extend(delta * [ None ])
|
lines[i].extend(delta * [None])
|
||||||
# grow last block
|
# grow last block
|
||||||
if len(b) > 0:
|
if len(b) > 0:
|
||||||
b[-1] += delta
|
b[-1] += delta
|
||||||
else:
|
else:
|
||||||
b = _create_block(delta)
|
b = _create_block(delta)
|
||||||
elif delta > 0:
|
elif delta > 0:
|
||||||
old_content.extend(delta * [ None ])
|
old_content.extend(delta * [None])
|
||||||
new_n = len(old_content)
|
new_n = len(old_content)
|
||||||
|
|
||||||
# update lines and blocks
|
# update lines and blocks
|
||||||
|
@ -3686,6 +3689,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
def merge_from_right_then_left(self):
|
def merge_from_right_then_left(self):
|
||||||
self._mergeBoth(True)
|
self._mergeBoth(True)
|
||||||
|
|
||||||
|
|
||||||
# convenience method for creating a menu according to a template
|
# convenience method for creating a menu according to a template
|
||||||
def createMenu(specs, radio=None, accel_group=None):
|
def createMenu(specs, radio=None, accel_group=None):
|
||||||
menu = Gtk.Menu.new()
|
menu = Gtk.Menu.new()
|
||||||
|
@ -3707,7 +3711,7 @@ def createMenu(specs, radio=None, accel_group=None):
|
||||||
item.connect('activate', cb, data)
|
item.connect('activate', cb, data)
|
||||||
if len(spec) > 3 and spec[3] is not None:
|
if len(spec) > 3 and spec[3] is not None:
|
||||||
image = Gtk.Image.new()
|
image = Gtk.Image.new()
|
||||||
image.set_from_stock(spec[3], Gtk.IconSize.MENU) # pylint: disable=no-member
|
image.set_from_stock(spec[3], Gtk.IconSize.MENU)
|
||||||
item.set_image(image)
|
item.set_image(image)
|
||||||
if accel_group is not None and len(spec) > 4:
|
if accel_group is not None and len(spec) > 4:
|
||||||
a = theResources.getKeyBindings('menu', spec[4])
|
a = theResources.getKeyBindings('menu', spec[4])
|
||||||
|
@ -3730,10 +3734,12 @@ def createMenu(specs, radio=None, accel_group=None):
|
||||||
menu.append(item)
|
menu.append(item)
|
||||||
return menu
|
return menu
|
||||||
|
|
||||||
|
|
||||||
ALPHANUMERIC_CLASS = 0
|
ALPHANUMERIC_CLASS = 0
|
||||||
WHITESPACE_CLASS = 1
|
WHITESPACE_CLASS = 1
|
||||||
OTHER_CLASS = 2
|
OTHER_CLASS = 2
|
||||||
|
|
||||||
|
|
||||||
# maps similar types of characters to a group
|
# maps similar types of characters to a group
|
||||||
def _get_character_class(c):
|
def _get_character_class(c):
|
||||||
if c.isalnum() or c == '_':
|
if c.isalnum() or c == '_':
|
||||||
|
@ -3742,11 +3748,12 @@ def _get_character_class(c):
|
||||||
return WHITESPACE_CLASS
|
return WHITESPACE_CLASS
|
||||||
return OTHER_CLASS
|
return OTHER_CLASS
|
||||||
|
|
||||||
|
|
||||||
# patience diff with difflib-style fallback
|
# patience diff with difflib-style fallback
|
||||||
def _patience_diff(a, b):
|
def _patience_diff(a, b):
|
||||||
matches, len_a, len_b = [], len(a), len(b)
|
matches, len_a, len_b = [], len(a), len(b)
|
||||||
if len_a and len_b:
|
if len_a and len_b:
|
||||||
blocks = [ (0, len_a, 0, len_b, 0) ]
|
blocks = [(0, len_a, 0, len_b, 0)]
|
||||||
while blocks:
|
while blocks:
|
||||||
start_a, end_a, start_b, end_b, match_idx = blocks.pop()
|
start_a, end_a, start_b, end_b, match_idx = blocks.pop()
|
||||||
aa, bb = a[start_a:end_a], b[start_b:end_b]
|
aa, bb = a[start_a:end_a], b[start_b:end_b]
|
||||||
|
@ -3822,6 +3829,7 @@ def _patience_diff(a, b):
|
||||||
matches.append((len_a, len_b, 0))
|
matches.append((len_a, len_b, 0))
|
||||||
return matches
|
return matches
|
||||||
|
|
||||||
|
|
||||||
# longest common subsequence of unique elements common to 'a' and 'b'
|
# longest common subsequence of unique elements common to 'a' and 'b'
|
||||||
def _patience_subsequence(a, b):
|
def _patience_subsequence(a, b):
|
||||||
# value unique lines by their order in each list
|
# value unique lines by their order in each list
|
||||||
|
@ -3877,6 +3885,7 @@ def _patience_subsequence(a, b):
|
||||||
result.reverse()
|
result.reverse()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
# difflib-style approximation of the longest common subsequence
|
# difflib-style approximation of the longest common subsequence
|
||||||
def _lcs_approx(a, b):
|
def _lcs_approx(a, b):
|
||||||
count1, lookup = {}, {}
|
count1, lookup = {}, {}
|
||||||
|
@ -3888,7 +3897,7 @@ def _lcs_approx(a, b):
|
||||||
if s in lookup:
|
if s in lookup:
|
||||||
lookup[s].append(i)
|
lookup[s].append(i)
|
||||||
else:
|
else:
|
||||||
lookup[s] = [ i ]
|
lookup[s] = [i]
|
||||||
if set(lookup).intersection(count1):
|
if set(lookup).intersection(count1):
|
||||||
# we have some common elements
|
# we have some common elements
|
||||||
# identify popular entries
|
# identify popular entries
|
||||||
|
@ -3921,7 +3930,7 @@ def _lcs_approx(a, b):
|
||||||
max_indices.append((ai, bi))
|
max_indices.append((ai, bi))
|
||||||
else:
|
else:
|
||||||
max_length = v
|
max_length = v
|
||||||
max_indices = [ (ai, bi) ]
|
max_indices = [(ai, bi)]
|
||||||
else:
|
else:
|
||||||
prev_get = prev_matches.get
|
prev_get = prev_matches.get
|
||||||
for bi in lookup[s]:
|
for bi in lookup[s]:
|
||||||
|
@ -3932,7 +3941,7 @@ def _lcs_approx(a, b):
|
||||||
max_indices.append((ai, bi))
|
max_indices.append((ai, bi))
|
||||||
else:
|
else:
|
||||||
max_length = v
|
max_length = v
|
||||||
max_indices = [ (ai, bi) ]
|
max_indices = [(ai, bi)]
|
||||||
prev_matches, matches = matches, {}
|
prev_matches, matches = matches, {}
|
||||||
if max_indices:
|
if max_indices:
|
||||||
# include any popular entries at the beginning
|
# include any popular entries at the beginning
|
||||||
|
@ -3950,18 +3959,22 @@ def _lcs_approx(a, b):
|
||||||
return aidx, bidx, nidx
|
return aidx, bidx, nidx
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
# True if the string ends with '\r\n'
|
# True if the string ends with '\r\n'
|
||||||
def _has_dos_line_ending(s):
|
def _has_dos_line_ending(s):
|
||||||
return s.endswith('\r\n')
|
return s.endswith('\r\n')
|
||||||
|
|
||||||
|
|
||||||
# True if the string ends with '\r'
|
# True if the string ends with '\r'
|
||||||
def _has_mac_line_ending(s):
|
def _has_mac_line_ending(s):
|
||||||
return s.endswith('\r')
|
return s.endswith('\r')
|
||||||
|
|
||||||
|
|
||||||
# True if the string ends with '\n' but not '\r\n'
|
# True if the string ends with '\n' but not '\r\n'
|
||||||
def _has_unix_line_ending(s):
|
def _has_unix_line_ending(s):
|
||||||
return s.endswith('\n') and not s.endswith('\r\n')
|
return s.endswith('\n') and not s.endswith('\r\n')
|
||||||
|
|
||||||
|
|
||||||
# returns the format mask for a list of strings
|
# returns the format mask for a list of strings
|
||||||
def _get_format(ss):
|
def _get_format(ss):
|
||||||
flags = 0
|
flags = 0
|
||||||
|
@ -3975,10 +3988,11 @@ def _get_format(ss):
|
||||||
flags |= utils.UNIX_FORMAT
|
flags |= utils.UNIX_FORMAT
|
||||||
return flags
|
return flags
|
||||||
|
|
||||||
|
|
||||||
# convenience method to change the line ending of a string
|
# convenience method to change the line ending of a string
|
||||||
def _convert_to_format(s, fmt):
|
def _convert_to_format(s, fmt):
|
||||||
if s is not None and fmt != 0:
|
if s is not None and fmt != 0:
|
||||||
old_format = _get_format([ s ])
|
old_format = _get_format([s])
|
||||||
if old_format != 0 and (old_format & fmt) == 0:
|
if old_format != 0 and (old_format & fmt) == 0:
|
||||||
s = utils.strip_eol(s)
|
s = utils.strip_eol(s)
|
||||||
# prefer the host line ending style
|
# prefer the host line ending style
|
||||||
|
@ -3996,6 +4010,7 @@ def _convert_to_format(s, fmt):
|
||||||
s += '\r'
|
s += '\r'
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
# Enforcing manual alignment is accomplished by dividing the lines of text into
|
# Enforcing manual alignment is accomplished by dividing the lines of text into
|
||||||
# sections that are matched independently. 'blocks' is an array of integers
|
# sections that are matched independently. 'blocks' is an array of integers
|
||||||
# describing how many lines (including null lines for spacing) that are in each
|
# describing how many lines (including null lines for spacing) that are in each
|
||||||
|
@ -4005,12 +4020,12 @@ def _convert_to_format(s, fmt):
|
||||||
# in this array so 'blocks' will be an empty array when there are no lines. A
|
# in this array so 'blocks' will be an empty array when there are no lines. A
|
||||||
# 'cut' at location 'i' means a line 'i-1' and line 'i' belong to different
|
# 'cut' at location 'i' means a line 'i-1' and line 'i' belong to different
|
||||||
# sections
|
# sections
|
||||||
|
|
||||||
def _create_block(n):
|
def _create_block(n):
|
||||||
if n > 0:
|
if n > 0:
|
||||||
return [ n ]
|
return [n]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
# returns the two sets of blocks after cutting at 'i'
|
# returns the two sets of blocks after cutting at 'i'
|
||||||
def _cut_blocks(i, blocks):
|
def _cut_blocks(i, blocks):
|
||||||
pre, post, nlines = [], [], 0
|
pre, post, nlines = [], [], 0
|
||||||
|
@ -4026,6 +4041,7 @@ def _cut_blocks(i, blocks):
|
||||||
nlines += b
|
nlines += b
|
||||||
return pre, post
|
return pre, post
|
||||||
|
|
||||||
|
|
||||||
# returns a set of blocks containing all of the cuts in the inputs
|
# returns a set of blocks containing all of the cuts in the inputs
|
||||||
def _merge_blocks(leftblocks, rightblocks):
|
def _merge_blocks(leftblocks, rightblocks):
|
||||||
leftblocks, rightblocks, b = leftblocks[:], rightblocks[:], []
|
leftblocks, rightblocks, b = leftblocks[:], rightblocks[:], []
|
||||||
|
@ -4043,6 +4059,7 @@ def _merge_blocks(leftblocks, rightblocks):
|
||||||
b.append(n)
|
b.append(n)
|
||||||
return b
|
return b
|
||||||
|
|
||||||
|
|
||||||
# utility method to simplify working with structures used to describe character
|
# utility method to simplify working with structures used to describe character
|
||||||
# differences of a line
|
# differences of a line
|
||||||
#
|
#
|
||||||
|
@ -4053,7 +4070,7 @@ def _merge_blocks(leftblocks, rightblocks):
|
||||||
# this method will return the union of two sorted lists of ranges
|
# this method will return the union of two sorted lists of ranges
|
||||||
def _merge_ranges(r1, r2):
|
def _merge_ranges(r1, r2):
|
||||||
r1, r2, result, start = r1[:], r2[:], [], 0
|
r1, r2, result, start = r1[:], r2[:], [], 0
|
||||||
rs = [ r1, r2 ]
|
rs = [r1, r2]
|
||||||
while len(r1) > 0 and len(r2) > 0:
|
while len(r1) > 0 and len(r2) > 0:
|
||||||
flags, start = 0, min(r1[0][0], r2[0][0])
|
flags, start = 0, min(r1[0][0], r2[0][0])
|
||||||
if start == r1[0][0]:
|
if start == r1[0][0]:
|
||||||
|
@ -4078,6 +4095,7 @@ def _merge_ranges(r1, r2):
|
||||||
result.extend(r2)
|
result.extend(r2)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
# eliminates lines that are spacing lines in all panes
|
# eliminates lines that are spacing lines in all panes
|
||||||
def _remove_null_lines(blocks, lines_set):
|
def _remove_null_lines(blocks, lines_set):
|
||||||
bi, bn, i = 0, 0, 0
|
bi, bn, i = 0, 0, 0
|
||||||
|
@ -4097,22 +4115,23 @@ def _remove_null_lines(blocks, lines_set):
|
||||||
bn += blocks[bi]
|
bn += blocks[bi]
|
||||||
bi += 1
|
bi += 1
|
||||||
|
|
||||||
|
|
||||||
# returns true if the string only contains whitespace characters
|
# returns true if the string only contains whitespace characters
|
||||||
def _is_blank(s):
|
def _is_blank(s):
|
||||||
for c in utils.whitespace:
|
for c in utils.whitespace:
|
||||||
s = s.replace(c, '')
|
s = s.replace(c, '')
|
||||||
return len(s) == 0
|
return len(s) == 0
|
||||||
|
|
||||||
|
|
||||||
# use Pango.SCALE instead of Pango.PIXELS to avoid overflow exception
|
# use Pango.SCALE instead of Pango.PIXELS to avoid overflow exception
|
||||||
def _pixels(size):
|
def _pixels(size):
|
||||||
return int(size / Pango.SCALE + 0.5)
|
return int(size / Pango.SCALE + 0.5)
|
||||||
|
|
||||||
|
|
||||||
# create 'title_changed' signal for FileDiffViewer
|
# create 'title_changed' signal for FileDiffViewer
|
||||||
# pylint: disable=line-too-long
|
GObject.signal_new('swapped-panes', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (int, int)) # noqa: E501
|
||||||
GObject.signal_new('swapped-panes', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (int, int))
|
GObject.signal_new('num-edits-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (int, )) # noqa: E501
|
||||||
GObject.signal_new('num-edits-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (int, ))
|
GObject.signal_new('mode-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, ()) # noqa: E501
|
||||||
GObject.signal_new('mode-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, ())
|
GObject.signal_new('cursor-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, ()) # noqa: E501
|
||||||
GObject.signal_new('cursor-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, ())
|
GObject.signal_new('syntax-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (str, )) # noqa: E501
|
||||||
GObject.signal_new('syntax-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (str, ))
|
GObject.signal_new('format-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (int, int)) # noqa: E501
|
||||||
GObject.signal_new('format-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (int, int))
|
|
||||||
# pylint: enable=line-too-long
|
|
||||||
|
|
Loading…
Reference in New Issue