commit
ef9e1b041f
|
@ -23,7 +23,7 @@ jobs:
|
||||||
- name: Pylint
|
- name: Pylint
|
||||||
uses: cclauss/GitHub-Action-for-pylint@master
|
uses: cclauss/GitHub-Action-for-pylint@master
|
||||||
with:
|
with:
|
||||||
args: "pylint src/vcs/ src/dialogs.py src/preferences.py src/resources.py src/utils.py src/widgets.py"
|
args: "apk add --no-cache gtk+3.0-dev gobject-introspection-dev ; pip install -r requirements.txt ; pylint src/**/*.py"
|
||||||
|
|
||||||
meson-build-test:
|
meson-build-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -24,7 +24,7 @@ ignore=CVS
|
||||||
|
|
||||||
# Add files or directories matching the regex patterns to the ignore-list. The
|
# Add files or directories matching the regex patterns to the ignore-list. The
|
||||||
# regex matches against paths.
|
# regex matches against paths.
|
||||||
ignore-paths=
|
ignore-paths=src/diffuse/main.py
|
||||||
|
|
||||||
# Files or directories matching the regex patterns are skipped. The regex
|
# Files or directories matching the regex patterns are skipped. The regex
|
||||||
# matches against base names, not paths.
|
# matches against base names, not paths.
|
||||||
|
@ -90,12 +90,10 @@ disable=raw-checker-failed,
|
||||||
# temporary silenced messages (ordered alphabetically)
|
# temporary silenced messages (ordered alphabetically)
|
||||||
duplicate-code,
|
duplicate-code,
|
||||||
fixme,
|
fixme,
|
||||||
import-error,
|
|
||||||
invalid-name,
|
invalid-name,
|
||||||
missing-class-docstring,
|
missing-class-docstring,
|
||||||
missing-function-docstring,
|
missing-function-docstring,
|
||||||
missing-module-docstring,
|
missing-module-docstring,
|
||||||
no-self-use,
|
|
||||||
too-few-public-methods,
|
too-few-public-methods,
|
||||||
too-many-arguments,
|
too-many-arguments,
|
||||||
too-many-branches,
|
too-many-branches,
|
||||||
|
|
|
@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- The new widgets.py is a bit fat though (~4000 lines)
|
- The new widgets.py is a bit fat though (~4000 lines)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- The intense code cleaning seems to have fixed a bug with the `-c` argument
|
||||||
|
(#120)
|
||||||
|
|
||||||
## [0.7.2] - 2021-11-18
|
## [0.7.2] - 2021-11-18
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
PyGObject~=3.40
|
||||||
|
pylint~=2.11
|
|
@ -26,7 +26,9 @@ gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import GObject, Gtk
|
from gi.repository import GObject, Gtk
|
||||||
# pylint: enable=wrong-import-position
|
# pylint: enable=wrong-import-position
|
||||||
|
|
||||||
|
# pylint: disable-next=no-name-in-module
|
||||||
from diffuse import constants
|
from diffuse import constants
|
||||||
|
|
||||||
from diffuse import utils
|
from diffuse import utils
|
||||||
|
|
||||||
# the about dialog
|
# the about dialog
|
||||||
|
@ -67,7 +69,8 @@ class FileChooserDialog(Gtk.FileChooserDialog):
|
||||||
# location for empty panes
|
# location for empty panes
|
||||||
last_chosen_folder = os.path.realpath(os.curdir)
|
last_chosen_folder = os.path.realpath(os.curdir)
|
||||||
|
|
||||||
def __current_folder_changed_cb(self, widget):
|
@staticmethod
|
||||||
|
def _current_folder_changed_cb(widget):
|
||||||
FileChooserDialog.last_chosen_folder = widget.get_current_folder()
|
FileChooserDialog.last_chosen_folder = widget.get_current_folder()
|
||||||
|
|
||||||
def __init__(self, title, parent, prefs, action, accept, rev=False):
|
def __init__(self, title, parent, prefs, action, accept, rev=False):
|
||||||
|
@ -96,7 +99,7 @@ class FileChooserDialog(Gtk.FileChooserDialog):
|
||||||
self.vbox.pack_start(hbox, False, False, 0) # pylint: disable=no-member
|
self.vbox.pack_start(hbox, False, False, 0) # pylint: disable=no-member
|
||||||
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)
|
||||||
|
|
||||||
def set_encoding(self, encoding):
|
def set_encoding(self, encoding):
|
||||||
self.encoding.set_text(encoding)
|
self.encoding.set_text(encoding)
|
||||||
|
@ -107,6 +110,7 @@ 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) # pylint: disable=no-member
|
|
@ -20,11 +20,9 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import codecs
|
import codecs
|
||||||
import difflib
|
|
||||||
import encodings
|
import encodings
|
||||||
import shlex
|
import shlex
|
||||||
import stat
|
import stat
|
||||||
import unicodedata
|
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
# pylint: disable=wrong-import-position
|
||||||
|
@ -40,14 +38,16 @@ from gi.repository import GObject, Gtk, Gdk, GdkPixbuf, Pango, PangoCairo
|
||||||
|
|
||||||
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
|
||||||
from diffuse.resources import Resources, theResources
|
from diffuse.resources import theResources
|
||||||
from diffuse.vcs.vcs_registry import VcsRegistry
|
from diffuse.vcs.vcs_registry import VcsRegistry
|
||||||
from diffuse.widgets import FileDiffViewer, ScrolledWindow
|
from diffuse.widgets import FileDiffViewer
|
||||||
from diffuse.widgets import LINE_MODE, CHAR_MODE, ALIGN_MODE
|
from diffuse.widgets import createMenu, LINE_MODE, CHAR_MODE, ALIGN_MODE
|
||||||
|
|
||||||
theVCSs = VcsRegistry()
|
theVCSs = VcsRegistry()
|
||||||
|
|
||||||
|
@ -933,11 +933,11 @@ class Diffuse(Gtk.Window):
|
||||||
utils.logDebug(f'Error writing {statepath}.')
|
utils.logDebug(f'Error writing {statepath}.')
|
||||||
|
|
||||||
# select viewer for a newly selected file in the confirm close dialogue
|
# select viewer for a newly selected file in the confirm close dialogue
|
||||||
def __confirmClose_row_activated_cb(self, tree, path, col, model):
|
def _confirmClose_row_activated_cb(self, tree, path, col, model):
|
||||||
self.notebook.set_current_page(self.notebook.page_num(model[path][3]))
|
self.notebook.set_current_page(self.notebook.page_num(model[path][3]))
|
||||||
|
|
||||||
# toggle save state for a file listed in the confirm close dialogue
|
# toggle save state for a file listed in the confirm close dialogue
|
||||||
def __confirmClose_toggle_cb(self, cell, path, model):
|
def _confirmClose_toggle_cb(self, cell, path, model):
|
||||||
model[path][0] = not model[path][0]
|
model[path][0] = not model[path][0]
|
||||||
|
|
||||||
# returns True if the list of viewers can be closed. The user will be
|
# returns True if the list of viewers can be closed. The user will be
|
||||||
|
@ -970,7 +970,7 @@ class Diffuse(Gtk.Window):
|
||||||
sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||||
treeview = Gtk.TreeView.new_with_model(model)
|
treeview = Gtk.TreeView.new_with_model(model)
|
||||||
r = Gtk.CellRendererToggle.new()
|
r = Gtk.CellRendererToggle.new()
|
||||||
r.connect('toggled', self.__confirmClose_toggle_cb, model)
|
r.connect('toggled', self._confirmClose_toggle_cb, model)
|
||||||
column = Gtk.TreeViewColumn(None, r)
|
column = Gtk.TreeViewColumn(None, r)
|
||||||
column.add_attribute(r, 'active', 0)
|
column.add_attribute(r, 'active', 0)
|
||||||
treeview.append_column(column)
|
treeview.append_column(column)
|
||||||
|
@ -984,7 +984,7 @@ class Diffuse(Gtk.Window):
|
||||||
column.set_resizable(True)
|
column.set_resizable(True)
|
||||||
column.set_sort_column_id(2)
|
column.set_sort_column_id(2)
|
||||||
treeview.append_column(column)
|
treeview.append_column(column)
|
||||||
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) # pylint: disable=no-member
|
||||||
|
@ -1190,7 +1190,7 @@ class Diffuse(Gtk.Window):
|
||||||
new_items = []
|
new_items = []
|
||||||
for item in items:
|
for item in items:
|
||||||
name, data = item
|
name, data = item
|
||||||
# get full path to an existing ancessor directory
|
# get full path to an existing ancestor directory
|
||||||
dn = os.path.abspath(name)
|
dn = os.path.abspath(name)
|
||||||
while not os.path.isdir(dn):
|
while not os.path.isdir(dn):
|
||||||
dn, old_dn = os.path.dirname(dn), dn
|
dn, old_dn = os.path.dirname(dn), dn
|
||||||
|
@ -1552,7 +1552,7 @@ def _create_menu_bar(specs, radio, accel_group):
|
||||||
menu_bar = Gtk.MenuBar.new()
|
menu_bar = Gtk.MenuBar.new()
|
||||||
for label, spec in specs:
|
for label, spec in specs:
|
||||||
menu = Gtk.MenuItem.new_with_mnemonic(label)
|
menu = Gtk.MenuItem.new_with_mnemonic(label)
|
||||||
menu.set_submenu(utils.createMenu(spec, radio, accel_group))
|
menu.set_submenu(createMenu(spec, radio, accel_group))
|
||||||
menu.set_use_underline(True)
|
menu.set_use_underline(True)
|
||||||
menu.show()
|
menu.show()
|
||||||
menu_bar.append(menu)
|
menu_bar.append(menu)
|
|
@ -0,0 +1,46 @@
|
||||||
|
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
|
||||||
|
moduledir = join_paths(pkgdatadir, 'diffuse')
|
||||||
|
sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))
|
||||||
|
|
||||||
|
python = import('python')
|
||||||
|
|
||||||
|
conf = configuration_data()
|
||||||
|
conf.set('PYTHON', python.find_installation('python3').path())
|
||||||
|
conf.set('pkgdatadir', pkgdatadir)
|
||||||
|
conf.set('localedir', join_paths(get_option('prefix'), get_option('localedir')))
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
input: 'diffuse.in',
|
||||||
|
output: 'diffuse',
|
||||||
|
configuration: conf,
|
||||||
|
install: true,
|
||||||
|
install_dir: get_option('bindir')
|
||||||
|
)
|
||||||
|
|
||||||
|
conf = configuration_data()
|
||||||
|
conf.set('VERSION', meson.project_version())
|
||||||
|
conf.set('sysconfigdir', sysconfdir)
|
||||||
|
conf.set('log_print_output', get_option('log_print_output'))
|
||||||
|
conf.set('log_print_stack', get_option('log_print_stack'))
|
||||||
|
conf.set('use_flatpak', get_option('use_flatpak'))
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
input: 'constants.py.in',
|
||||||
|
output: 'constants.py',
|
||||||
|
configuration: conf,
|
||||||
|
install: true,
|
||||||
|
install_dir: moduledir
|
||||||
|
)
|
||||||
|
|
||||||
|
diffuse_sources = [
|
||||||
|
'__init__.py',
|
||||||
|
'dialogs.py',
|
||||||
|
'main.py',
|
||||||
|
'preferences.py',
|
||||||
|
'resources.py',
|
||||||
|
'utils.py',
|
||||||
|
'widgets.py',
|
||||||
|
]
|
||||||
|
|
||||||
|
install_data(diffuse_sources, install_dir: moduledir)
|
||||||
|
install_subdir('vcs', install_dir: moduledir, strip_directory: false)
|
|
@ -29,9 +29,11 @@ gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
# pylint: enable=wrong-import-position
|
# pylint: enable=wrong-import-position
|
||||||
|
|
||||||
from diffuse import utils
|
# pylint: disable-next=no-name-in-module
|
||||||
from diffuse import constants
|
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:
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
|
@ -29,8 +29,8 @@ gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
# pylint: enable=wrong-import-position
|
# pylint: enable=wrong-import-position
|
||||||
|
|
||||||
|
# pylint: disable-next=no-name-in-module
|
||||||
from diffuse import constants
|
from diffuse import constants
|
||||||
from diffuse.resources import theResources
|
|
||||||
|
|
||||||
# convenience class for displaying a message dialogue
|
# convenience class for displaying a message dialogue
|
||||||
class MessageDialog(Gtk.MessageDialog):
|
class MessageDialog(Gtk.MessageDialog):
|
||||||
|
@ -272,50 +272,6 @@ def step_adjustment(adj, delta):
|
||||||
v = min(v, int(adj.get_upper() - adj.get_page_size()))
|
v = min(v, int(adj.get_upper() - adj.get_page_size()))
|
||||||
adj.set_value(v)
|
adj.set_value(v)
|
||||||
|
|
||||||
# convenience method for creating a menu according to a template
|
|
||||||
def createMenu(specs, radio=None, accel_group=None):
|
|
||||||
menu = Gtk.Menu.new()
|
|
||||||
for spec in specs:
|
|
||||||
if len(spec) > 0:
|
|
||||||
if len(spec) > 7 and spec[7] is not None:
|
|
||||||
g, k = spec[7]
|
|
||||||
if g not in radio:
|
|
||||||
item = Gtk.RadioMenuItem.new_with_mnemonic_from_widget(None, spec[0])
|
|
||||||
radio[g] = (item, {})
|
|
||||||
else:
|
|
||||||
item = Gtk.RadioMenuItem.new_with_mnemonic_from_widget(radio[g][0], spec[0])
|
|
||||||
radio[g][1][k] = item
|
|
||||||
else:
|
|
||||||
item = Gtk.ImageMenuItem.new_with_mnemonic(spec[0])
|
|
||||||
cb = spec[1]
|
|
||||||
if cb is not None:
|
|
||||||
data = spec[2]
|
|
||||||
item.connect('activate', cb, data)
|
|
||||||
if len(spec) > 3 and spec[3] is not None:
|
|
||||||
image = Gtk.Image.new()
|
|
||||||
image.set_from_stock(spec[3], Gtk.IconSize.MENU) # pylint: disable=no-member
|
|
||||||
item.set_image(image)
|
|
||||||
if accel_group is not None and len(spec) > 4:
|
|
||||||
a = theResources.getKeyBindings('menu', spec[4])
|
|
||||||
if len(a) > 0:
|
|
||||||
key, modifier = a[0]
|
|
||||||
item.add_accelerator(
|
|
||||||
'activate',
|
|
||||||
accel_group,
|
|
||||||
key,
|
|
||||||
modifier,
|
|
||||||
Gtk.AccelFlags.VISIBLE)
|
|
||||||
if len(spec) > 5:
|
|
||||||
item.set_sensitive(spec[5])
|
|
||||||
if len(spec) > 6 and spec[6] is not None:
|
|
||||||
item.set_submenu(createMenu(spec[6], radio, accel_group))
|
|
||||||
item.set_use_underline(True)
|
|
||||||
else:
|
|
||||||
item = Gtk.SeparatorMenuItem.new()
|
|
||||||
item.show()
|
|
||||||
menu.append(item)
|
|
||||||
return menu
|
|
||||||
|
|
||||||
|
|
||||||
# masks used to indicate the presence of particular line endings
|
# masks used to indicate the presence of particular line endings
|
||||||
DOS_FORMAT = 1
|
DOS_FORMAT = 1
|
|
@ -60,7 +60,7 @@ class Rcs(VcsInterface):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# simulate use of popen with xargs to read the output of a command
|
# simulate use of popen with xargs to read the output of a command
|
||||||
def _popen_xargs_readlines(self, dn, cmd, args, prefs, bash_pref):
|
def _popen_xargs_readlines(self, cmd, args, prefs, bash_pref):
|
||||||
# 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')
|
||||||
|
@ -85,7 +85,7 @@ class Rcs(VcsInterface):
|
||||||
s += len(args[i]) + 1
|
s += len(args[i]) + 1
|
||||||
i += 1
|
i += 1
|
||||||
if i == len(args) or not f:
|
if i == len(args) or not f:
|
||||||
ss.extend(utils.popenReadLines(dn, a, prefs, bash_pref))
|
ss.extend(utils.popenReadLines(self.root, a, prefs, bash_pref))
|
||||||
s, a = 0, []
|
s, a = 0, []
|
||||||
return ss
|
return ss
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ class Rcs(VcsInterface):
|
||||||
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(self.root, cmd, args, prefs, 'rcs_bash'):
|
for line in self._popen_xargs_readlines(cmd, args, prefs, 'rcs_bash'):
|
||||||
# parse response
|
# parse response
|
||||||
if line.startswith('Working file: '):
|
if line.startswith('Working file: '):
|
||||||
k = prefs.convertToNativePath(line[14:])
|
k = prefs.convertToNativePath(line[14:])
|
|
@ -23,18 +23,22 @@ from diffuse import utils
|
||||||
from diffuse.vcs.svn import Svn
|
from diffuse.vcs.svn import Svn
|
||||||
|
|
||||||
class Svk(Svn):
|
class Svk(Svn):
|
||||||
def _getVcs(self):
|
@staticmethod
|
||||||
|
def _getVcs():
|
||||||
return 'svk'
|
return 'svk'
|
||||||
|
|
||||||
def _getURLPrefix(self):
|
@staticmethod
|
||||||
|
def _getURLPrefix():
|
||||||
return 'Depot Path: '
|
return 'Depot Path: '
|
||||||
|
|
||||||
def _parseStatusLine(self, s):
|
@staticmethod
|
||||||
|
def _parseStatusLine(s):
|
||||||
if len(s) < 4 or s[0] not in 'ACDMR':
|
if len(s) < 4 or s[0] not in 'ACDMR':
|
||||||
return '', ''
|
return '', ''
|
||||||
return s[0], s[4:]
|
return s[0], s[4:]
|
||||||
|
|
||||||
def _getPreviousRevision(self, rev):
|
@staticmethod
|
||||||
|
def _getPreviousRevision(rev):
|
||||||
if rev is None:
|
if rev is None:
|
||||||
return 'HEAD'
|
return 'HEAD'
|
||||||
if rev.endswith('@'):
|
if rev.endswith('@'):
|
|
@ -31,13 +31,16 @@ class Svn(VcsInterface):
|
||||||
VcsInterface.__init__(self, root)
|
VcsInterface.__init__(self, root)
|
||||||
self.url = None
|
self.url = None
|
||||||
|
|
||||||
def _getVcs(self):
|
@staticmethod
|
||||||
|
def _getVcs():
|
||||||
return 'svn'
|
return 'svn'
|
||||||
|
|
||||||
def _getURLPrefix(self):
|
@staticmethod
|
||||||
|
def _getURLPrefix():
|
||||||
return 'URL: '
|
return 'URL: '
|
||||||
|
|
||||||
def _parseStatusLine(self, s):
|
@staticmethod
|
||||||
|
def _parseStatusLine(s):
|
||||||
if len(s) < 8 or s[0] not in 'ACDMR':
|
if len(s) < 8 or s[0] not in 'ACDMR':
|
||||||
return '', ''
|
return '', ''
|
||||||
# subversion 1.6 adds a new column
|
# subversion 1.6 adds a new column
|
||||||
|
@ -46,7 +49,8 @@ class Svn(VcsInterface):
|
||||||
k += 1
|
k += 1
|
||||||
return s[0], s[k:]
|
return s[0], s[k:]
|
||||||
|
|
||||||
def _getPreviousRevision(self, rev):
|
@staticmethod
|
||||||
|
def _getPreviousRevision(rev):
|
||||||
if rev is None:
|
if rev is None:
|
||||||
return 'BASE'
|
return 'BASE'
|
||||||
m = int(rev)
|
m = int(rev)
|
|
@ -1649,7 +1649,8 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# scroll vertically to current line
|
# scroll vertically to current line
|
||||||
self._ensure_line_is_visible(current_line)
|
self._ensure_line_is_visible(current_line)
|
||||||
|
|
||||||
def __set_clipboard_text(self, clipboard, s):
|
@staticmethod
|
||||||
|
def _set_clipboard_text(clipboard, s):
|
||||||
# remove embedded nulls as the clipboard cannot handle them
|
# remove embedded nulls as the clipboard cannot handle them
|
||||||
Gtk.Clipboard.get(clipboard).set_text(s.replace('\0', ''), -1)
|
Gtk.Clipboard.get(clipboard).set_text(s.replace('\0', ''), -1)
|
||||||
|
|
||||||
|
@ -1673,7 +1674,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
self.selection_char = sj
|
self.selection_char = sj
|
||||||
|
|
||||||
if extend:
|
if extend:
|
||||||
self.__set_clipboard_text(Gdk.SELECTION_PRIMARY, self.getSelectedText())
|
self._set_clipboard_text(Gdk.SELECTION_PRIMARY, self.getSelectedText())
|
||||||
|
|
||||||
self._cursor_position_changed(True)
|
self._cursor_position_changed(True)
|
||||||
self.emit('cursor_changed')
|
self.emit('cursor_changed')
|
||||||
|
@ -1833,7 +1834,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
can_swap = (f != self.current_pane)
|
can_swap = (f != self.current_pane)
|
||||||
|
|
||||||
# pylint: disable=line-too-long
|
# pylint: disable=line-too-long
|
||||||
menu = utils.createMenu(
|
menu = createMenu(
|
||||||
[ [_('Align with Selection'), self.align_with_selection_cb, [f, i], Gtk.STOCK_EXECUTE, None, can_align],
|
[ [_('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],
|
||||||
|
@ -2922,7 +2923,7 @@ class FileDiffViewer(Gtk.Grid):
|
||||||
# 'copy' action
|
# 'copy' action
|
||||||
def copy(self):
|
def copy(self):
|
||||||
if self.mode in (LINE_MODE, CHAR_MODE):
|
if self.mode in (LINE_MODE, CHAR_MODE):
|
||||||
self.__set_clipboard_text(Gdk.SELECTION_CLIPBOARD, self.getSelectedText())
|
self._set_clipboard_text(Gdk.SELECTION_CLIPBOARD, self.getSelectedText())
|
||||||
|
|
||||||
# 'cut' action
|
# 'cut' action
|
||||||
def cut(self):
|
def cut(self):
|
||||||
|
@ -3685,6 +3686,50 @@ 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
|
||||||
|
def createMenu(specs, radio=None, accel_group=None):
|
||||||
|
menu = Gtk.Menu.new()
|
||||||
|
for spec in specs:
|
||||||
|
if len(spec) > 0:
|
||||||
|
if len(spec) > 7 and spec[7] is not None:
|
||||||
|
g, k = spec[7]
|
||||||
|
if g not in radio:
|
||||||
|
item = Gtk.RadioMenuItem.new_with_mnemonic_from_widget(None, spec[0])
|
||||||
|
radio[g] = (item, {})
|
||||||
|
else:
|
||||||
|
item = Gtk.RadioMenuItem.new_with_mnemonic_from_widget(radio[g][0], spec[0])
|
||||||
|
radio[g][1][k] = item
|
||||||
|
else:
|
||||||
|
item = Gtk.ImageMenuItem.new_with_mnemonic(spec[0])
|
||||||
|
cb = spec[1]
|
||||||
|
if cb is not None:
|
||||||
|
data = spec[2]
|
||||||
|
item.connect('activate', cb, data)
|
||||||
|
if len(spec) > 3 and spec[3] is not None:
|
||||||
|
image = Gtk.Image.new()
|
||||||
|
image.set_from_stock(spec[3], Gtk.IconSize.MENU) # pylint: disable=no-member
|
||||||
|
item.set_image(image)
|
||||||
|
if accel_group is not None and len(spec) > 4:
|
||||||
|
a = theResources.getKeyBindings('menu', spec[4])
|
||||||
|
if len(a) > 0:
|
||||||
|
key, modifier = a[0]
|
||||||
|
item.add_accelerator(
|
||||||
|
'activate',
|
||||||
|
accel_group,
|
||||||
|
key,
|
||||||
|
modifier,
|
||||||
|
Gtk.AccelFlags.VISIBLE)
|
||||||
|
if len(spec) > 5:
|
||||||
|
item.set_sensitive(spec[5])
|
||||||
|
if len(spec) > 6 and spec[6] is not None:
|
||||||
|
item.set_submenu(createMenu(spec[6], radio, accel_group))
|
||||||
|
item.set_use_underline(True)
|
||||||
|
else:
|
||||||
|
item = Gtk.SeparatorMenuItem.new()
|
||||||
|
item.show()
|
||||||
|
menu.append(item)
|
||||||
|
return menu
|
||||||
|
|
||||||
ALPHANUMERIC_CLASS = 0
|
ALPHANUMERIC_CLASS = 0
|
||||||
WHITESPACE_CLASS = 1
|
WHITESPACE_CLASS = 1
|
||||||
OTHER_CLASS = 2
|
OTHER_CLASS = 2
|
|
@ -1,44 +1 @@
|
||||||
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
|
subdir('diffuse')
|
||||||
moduledir = join_paths(pkgdatadir, meson.project_name())
|
|
||||||
sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))
|
|
||||||
|
|
||||||
python = import('python')
|
|
||||||
|
|
||||||
conf = configuration_data()
|
|
||||||
conf.set('PYTHON', python.find_installation('python3').path())
|
|
||||||
conf.set('VERSION', meson.project_version())
|
|
||||||
conf.set('localedir', join_paths(get_option('prefix'), get_option('localedir')))
|
|
||||||
conf.set('pkgdatadir', pkgdatadir)
|
|
||||||
conf.set('sysconfigdir', sysconfdir)
|
|
||||||
conf.set('log_print_output', get_option('log_print_output'))
|
|
||||||
conf.set('log_print_stack', get_option('log_print_stack'))
|
|
||||||
conf.set('use_flatpak', get_option('use_flatpak'))
|
|
||||||
|
|
||||||
configure_file(
|
|
||||||
input: 'diffuse.in',
|
|
||||||
output: 'diffuse',
|
|
||||||
configuration: conf,
|
|
||||||
install: true,
|
|
||||||
install_dir: get_option('bindir')
|
|
||||||
)
|
|
||||||
|
|
||||||
configure_file(
|
|
||||||
input: 'constants.py.in',
|
|
||||||
output: 'constants.py',
|
|
||||||
configuration: conf,
|
|
||||||
install: true,
|
|
||||||
install_dir: moduledir
|
|
||||||
)
|
|
||||||
|
|
||||||
diffuse_sources = [
|
|
||||||
'__init__.py',
|
|
||||||
'dialogs.py',
|
|
||||||
'main.py',
|
|
||||||
'preferences.py',
|
|
||||||
'resources.py',
|
|
||||||
'utils.py',
|
|
||||||
'widgets.py',
|
|
||||||
]
|
|
||||||
|
|
||||||
install_data(diffuse_sources, install_dir: moduledir)
|
|
||||||
install_subdir('vcs', install_dir: moduledir, strip_directory: false)
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ def mkdir(s):
|
||||||
|
|
||||||
# copies a file to 'dest'
|
# copies a file to 'dest'
|
||||||
def copyFile(src, dest, use_text_mode=False,enc=None):
|
def copyFile(src, dest, use_text_mode=False,enc=None):
|
||||||
print 'copying "%s" to "%s"' % (src, dest)
|
print('copying "%s" to "%s"' % (src, dest))
|
||||||
if use_text_mode:
|
if use_text_mode:
|
||||||
r, w = 'r', 'w'
|
r, w = 'r', 'w'
|
||||||
else:
|
else:
|
||||||
|
@ -53,7 +53,7 @@ def copyFile(src, dest, use_text_mode=False,enc=None):
|
||||||
|
|
||||||
# recursively copies a directory to 'dest'
|
# recursively copies a directory to 'dest'
|
||||||
def copyDir(src, dest):
|
def copyDir(src, dest):
|
||||||
print 'copying "%s" to "%s"' % (src, dest)
|
print('copying "%s" to "%s"' % (src, dest))
|
||||||
mkdir(dest)
|
mkdir(dest)
|
||||||
for f in os.listdir(src):
|
for f in os.listdir(src):
|
||||||
s = os.path.join(src, f)
|
s = os.path.join(src, f)
|
||||||
|
@ -128,7 +128,7 @@ locale_dir = os.path.join(gtk_dir, 'share\\locale')
|
||||||
for s in glob.glob('..\\po\\*.po'):
|
for s in glob.glob('..\\po\\*.po'):
|
||||||
lang = s[16:-3]
|
lang = s[16:-3]
|
||||||
# Diffuse localisations
|
# Diffuse localisations
|
||||||
print 'Compiling %s translation' % (lang, )
|
print('Compiling %s translation' % (lang, ))
|
||||||
d = 'dist'
|
d = 'dist'
|
||||||
for p in [ 'locale', lang, 'LC_MESSAGES' ]:
|
for p in [ 'locale', lang, 'LC_MESSAGES' ]:
|
||||||
d = os.path.join(d, p)
|
d = os.path.join(d, p)
|
||||||
|
@ -236,4 +236,4 @@ if os.system('iscc diffuse.iss /F%s' % (INSTALLER, )) != 0:
|
||||||
# Declare success.
|
# Declare success.
|
||||||
#
|
#
|
||||||
|
|
||||||
print 'Successfully created "%s".' % (INSTALLER, )
|
print('Successfully created "%s".' % (INSTALLER, ))
|
||||||
|
|
Loading…
Reference in New Issue