Add static typing for main
This commit is contained in:
parent
0a2d3cc3e0
commit
86137e90c5
|
@ -26,7 +26,7 @@ import stat
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from diffuse import constants
|
from diffuse import constants
|
||||||
|
@ -35,9 +35,10 @@ from diffuse.dialogs import AboutDialog, FileChooserDialog, NumericDialog, Searc
|
||||||
from diffuse.preferences import Preferences
|
from diffuse.preferences import Preferences
|
||||||
from diffuse.resources import theResources
|
from diffuse.resources import theResources
|
||||||
from diffuse.utils import LineEnding
|
from diffuse.utils import LineEnding
|
||||||
|
from diffuse.vcs.vcs_interface import VcsInterface
|
||||||
from diffuse.vcs.vcs_registry import VcsRegistry
|
from diffuse.vcs.vcs_registry import VcsRegistry
|
||||||
from diffuse.widgets import FileDiffViewerBase
|
from diffuse.widgets import FileDiffViewerBase, EditMode
|
||||||
from diffuse.widgets import createMenu, LINE_MODE, CHAR_MODE, ALIGN_MODE
|
from diffuse.widgets import createMenu
|
||||||
|
|
||||||
import gi # type: ignore
|
import gi # type: ignore
|
||||||
gi.require_version('GObject', '2.0')
|
gi.require_version('GObject', '2.0')
|
||||||
|
@ -57,7 +58,7 @@ theVCSs = VcsRegistry()
|
||||||
# make this a Gtk.EventBox so signals can be connected for MMB and RMB button
|
# make this a Gtk.EventBox so signals can be connected for MMB and RMB button
|
||||||
# presses.
|
# presses.
|
||||||
class NotebookTab(Gtk.EventBox):
|
class NotebookTab(Gtk.EventBox):
|
||||||
def __init__(self, name, stock):
|
def __init__(self, name: str, stock: str) -> None:
|
||||||
Gtk.EventBox.__init__(self)
|
Gtk.EventBox.__init__(self)
|
||||||
self.set_visible_window(False)
|
self.set_visible_window(False)
|
||||||
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||||
|
@ -66,13 +67,16 @@ class NotebookTab(Gtk.EventBox):
|
||||||
image.set_from_stock(stock, Gtk.IconSize.MENU)
|
image.set_from_stock(stock, Gtk.IconSize.MENU)
|
||||||
hbox.pack_start(image, False, False, 5)
|
hbox.pack_start(image, False, False, 5)
|
||||||
image.show()
|
image.show()
|
||||||
self.label = label = Gtk.Label.new(name)
|
|
||||||
|
label = Gtk.Label.new(name)
|
||||||
# left justify the widget
|
# left justify the widget
|
||||||
label.set_xalign(0.0)
|
label.set_xalign(0.0)
|
||||||
label.set_yalign(0.5)
|
label.set_yalign(0.5)
|
||||||
hbox.pack_start(label, True, True, 0)
|
hbox.pack_start(label, True, True, 0)
|
||||||
label.show()
|
label.show()
|
||||||
self.button = button = Gtk.Button.new()
|
self.label = label
|
||||||
|
|
||||||
|
button = Gtk.Button.new()
|
||||||
button.set_relief(Gtk.ReliefStyle.NONE)
|
button.set_relief(Gtk.ReliefStyle.NONE)
|
||||||
image = Gtk.Image.new()
|
image = Gtk.Image.new()
|
||||||
image.set_from_stock(Gtk.STOCK_CLOSE, Gtk.IconSize.MENU)
|
image.set_from_stock(Gtk.STOCK_CLOSE, Gtk.IconSize.MENU)
|
||||||
|
@ -81,13 +85,15 @@ class NotebookTab(Gtk.EventBox):
|
||||||
button.set_tooltip_text(_('Close Tab'))
|
button.set_tooltip_text(_('Close Tab'))
|
||||||
hbox.pack_start(button, False, False, 0)
|
hbox.pack_start(button, False, False, 0)
|
||||||
button.show()
|
button.show()
|
||||||
|
self.button = button
|
||||||
|
|
||||||
self.add(hbox)
|
self.add(hbox)
|
||||||
hbox.show()
|
hbox.show()
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self) -> str:
|
||||||
return self.label.get_text()
|
return self.label.get_text()
|
||||||
|
|
||||||
def set_text(self, s):
|
def set_text(self, s: str) -> None:
|
||||||
self.label.set_text(s)
|
self.label.set_text(s)
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,7 +105,7 @@ class FileInfo:
|
||||||
# name of codec used to translate the file contents to unicode text
|
# name of codec used to translate the file contents to unicode text
|
||||||
self.encoding = encoding
|
self.encoding = encoding
|
||||||
# the VCS object
|
# the VCS object
|
||||||
self.vcs = vcs
|
self.vcs: VcsInterface = vcs
|
||||||
# revision used to retrieve file from the VCS
|
# revision used to retrieve file from the VCS
|
||||||
self.revision = revision
|
self.revision = revision
|
||||||
# alternate text to display instead of the actual file name
|
# alternate text to display instead of the actual file name
|
||||||
|
@ -147,7 +153,7 @@ class Diffuse(Gtk.Window):
|
||||||
self.emit(s)
|
self.emit(s)
|
||||||
|
|
||||||
# creates an appropriate title for the pane header
|
# creates an appropriate title for the pane header
|
||||||
def updateTitle(self):
|
def updateTitle(self) -> None:
|
||||||
ss = []
|
ss = []
|
||||||
info = self.info
|
info = self.info
|
||||||
if info.label is not None:
|
if info.label is not None:
|
||||||
|
@ -166,7 +172,7 @@ class Diffuse(Gtk.Window):
|
||||||
self.emit('title_changed')
|
self.emit('title_changed')
|
||||||
|
|
||||||
# set num edits
|
# set num edits
|
||||||
def setEdits(self, has_edits):
|
def setEdits(self, has_edits: bool) -> None:
|
||||||
if self.has_edits != has_edits:
|
if self.has_edits != has_edits:
|
||||||
self.has_edits = has_edits
|
self.has_edits = has_edits
|
||||||
self.updateTitle()
|
self.updateTitle()
|
||||||
|
@ -198,8 +204,8 @@ class Diffuse(Gtk.Window):
|
||||||
self.show_all()
|
self.show_all()
|
||||||
|
|
||||||
# set the cursor label
|
# set the cursor label
|
||||||
def updateCursor(self, viewer, f):
|
def updateCursor(self, viewer: FileDiffViewerBase, f: int) -> None:
|
||||||
if viewer.mode == CHAR_MODE and viewer.current_pane == f:
|
if viewer.mode == EditMode.CHAR and viewer.current_pane == f:
|
||||||
# # TODO: Find a fix for the column bug (resizing issue when editing a line)
|
# # TODO: Find a fix for the column bug (resizing issue when editing a line)
|
||||||
# j = viewer.current_char
|
# j = viewer.current_char
|
||||||
# if j > 0:
|
# if j > 0:
|
||||||
|
@ -212,7 +218,7 @@ class Diffuse(Gtk.Window):
|
||||||
self.cursor.set_text(s)
|
self.cursor.set_text(s)
|
||||||
|
|
||||||
# set the format label
|
# set the format label
|
||||||
def setFormat(self, s):
|
def setFormat(self, s: LineEnding) -> None:
|
||||||
v = []
|
v = []
|
||||||
if s & LineEnding.DOS_FORMAT:
|
if s & LineEnding.DOS_FORMAT:
|
||||||
v.append('DOS')
|
v.append('DOS')
|
||||||
|
@ -223,19 +229,19 @@ class Diffuse(Gtk.Window):
|
||||||
self.format.set_text('/'.join(v))
|
self.format.set_text('/'.join(v))
|
||||||
|
|
||||||
# set the format label
|
# set the format label
|
||||||
def setEncoding(self, s):
|
def setEncoding(self, s: str) -> None:
|
||||||
if s is None:
|
if s is None:
|
||||||
s = ''
|
s = ''
|
||||||
self.encoding.set_text(s)
|
self.encoding.set_text(s)
|
||||||
|
|
||||||
def __init__(self, n, prefs, title):
|
def __init__(self, n: int, prefs: Preferences, title: str) -> None:
|
||||||
FileDiffViewerBase.__init__(self, n, prefs)
|
super().__init__(n, prefs)
|
||||||
|
|
||||||
self.title = title
|
self.title = title
|
||||||
self.status = ''
|
self.status: Optional[str] = ''
|
||||||
|
|
||||||
self.headers = []
|
self.headers: List[Diffuse.FileDiffViewer.PaneHeader] = []
|
||||||
self.footers = []
|
self.footers: List[Diffuse.FileDiffViewer.PaneFooter] = []
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
# pane header
|
# pane header
|
||||||
w = Diffuse.FileDiffViewer.PaneHeader()
|
w = Diffuse.FileDiffViewer.PaneHeader()
|
||||||
|
@ -272,7 +278,7 @@ class Diffuse(Gtk.Window):
|
||||||
|
|
||||||
# convenience method to request confirmation before loading a file if
|
# convenience method to request confirmation before loading a file if
|
||||||
# it will cause existing edits to be lost
|
# it will cause existing edits to be lost
|
||||||
def loadFromInfo(self, f, info):
|
def loadFromInfo(self, f: int, info: FileInfo) -> None:
|
||||||
if self.headers[f].has_edits:
|
if self.headers[f].has_edits:
|
||||||
# warn users of any unsaved changes they might lose
|
# warn users of any unsaved changes they might lose
|
||||||
dialog = Gtk.MessageDialog(
|
dialog = Gtk.MessageDialog(
|
||||||
|
@ -358,7 +364,7 @@ class Diffuse(Gtk.Window):
|
||||||
# load a new file into pane 'f'
|
# load a new file into pane 'f'
|
||||||
# 'info' indicates the name of the file and how to retrieve it from the
|
# 'info' indicates the name of the file and how to retrieve it from the
|
||||||
# version control system if applicable
|
# version control system if applicable
|
||||||
def load(self, f, info):
|
def load(self, f: int, info: FileInfo) -> None:
|
||||||
name = info.name
|
name = info.name
|
||||||
encoding = info.encoding
|
encoding = info.encoding
|
||||||
stat = None
|
stat = None
|
||||||
|
@ -371,7 +377,7 @@ class Diffuse(Gtk.Window):
|
||||||
if rev is None:
|
if rev is None:
|
||||||
# load the contents of a plain file
|
# load the contents of a plain file
|
||||||
with open(name, 'rb') as fd:
|
with open(name, 'rb') as fd:
|
||||||
s = fd.read()
|
contents = fd.read()
|
||||||
# get the file's modification times so we can detect changes
|
# get the file's modification times so we can detect changes
|
||||||
stat = os.stat(name)
|
stat = os.stat(name)
|
||||||
else:
|
else:
|
||||||
|
@ -379,12 +385,12 @@ class Diffuse(Gtk.Window):
|
||||||
raise IOError('Not under version control.')
|
raise IOError('Not under version control.')
|
||||||
fullname = os.path.abspath(name)
|
fullname = os.path.abspath(name)
|
||||||
# retrieve the revision from the version control system
|
# retrieve the revision from the version control system
|
||||||
s = info.vcs.getRevision(self.prefs, fullname, rev)
|
contents = info.vcs.getRevision(self.prefs, fullname, rev)
|
||||||
# convert file contents to unicode
|
# convert file contents to unicode
|
||||||
if encoding is None:
|
if encoding is None:
|
||||||
s, encoding = self.prefs.convertToUnicode(s)
|
s, encoding = self.prefs.convertToUnicode(contents)
|
||||||
else:
|
else:
|
||||||
s = str(s, encoding=encoding)
|
s = str(contents, encoding=encoding)
|
||||||
ss = utils.splitlines(s)
|
ss = utils.splitlines(s)
|
||||||
except (IOError, OSError, UnicodeDecodeError, LookupError):
|
except (IOError, OSError, UnicodeDecodeError, LookupError):
|
||||||
# FIXME: this can occur before the toplevel window is drawn
|
# FIXME: this can occur before the toplevel window is drawn
|
||||||
|
@ -408,7 +414,7 @@ class Diffuse(Gtk.Window):
|
||||||
self.setSyntax(syntax)
|
self.setSyntax(syntax)
|
||||||
|
|
||||||
# load a new file into pane 'f'
|
# load a new file into pane 'f'
|
||||||
def open_file(self, f, reload=False):
|
def open_file(self, f: int, reload: bool = False) -> None:
|
||||||
h = self.headers[f]
|
h = self.headers[f]
|
||||||
info = h.info
|
info = h.info
|
||||||
if not reload:
|
if not reload:
|
||||||
|
@ -487,7 +493,7 @@ class Diffuse(Gtk.Window):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# save contents of pane 'f' to file
|
# save contents of pane 'f' to file
|
||||||
def save_file(self, f, save_as=False):
|
def save_file(self, f: int, save_as: bool = False) -> bool:
|
||||||
h = self.headers[f]
|
h = self.headers[f]
|
||||||
info = h.info
|
info = h.info
|
||||||
name, encoding, rev, label = info.name, info.encoding, info.revision, info.label
|
name, encoding, rev, label = info.name, info.encoding, info.revision, info.label
|
||||||
|
@ -642,15 +648,15 @@ class Diffuse(Gtk.Window):
|
||||||
self.updateStatus()
|
self.updateStatus()
|
||||||
|
|
||||||
# update the viewer's current status message
|
# update the viewer's current status message
|
||||||
def updateStatus(self):
|
def updateStatus(self) -> None:
|
||||||
if self.mode == LINE_MODE:
|
if self.mode == EditMode.LINE:
|
||||||
s = _(
|
s = _(
|
||||||
'Press the enter key or double click to edit. Press the space bar or use the '
|
'Press the enter key or double click to edit. Press the space bar or use the '
|
||||||
'RMB menu to manually align.'
|
'RMB menu to manually align.'
|
||||||
)
|
)
|
||||||
elif self.mode == CHAR_MODE:
|
elif self.mode == EditMode.CHAR:
|
||||||
s = _('Press the escape key to finish editing.')
|
s = _('Press the escape key to finish editing.')
|
||||||
elif self.mode == ALIGN_MODE:
|
elif self.mode == EditMode.ALIGN:
|
||||||
s = _(
|
s = _(
|
||||||
'Select target line and press the space bar to align. Press the escape key to '
|
'Select target line and press the space bar to align. Press the escape key to '
|
||||||
'cancel.'
|
'cancel.'
|
||||||
|
@ -661,7 +667,7 @@ class Diffuse(Gtk.Window):
|
||||||
self.emit('status_changed', s)
|
self.emit('status_changed', s)
|
||||||
|
|
||||||
# gets the status bar text
|
# gets the status bar text
|
||||||
def getStatus(self):
|
def getStatus(self) -> Optional[str]:
|
||||||
return self.status
|
return self.status
|
||||||
|
|
||||||
# callback to display the cursor in a pane
|
# callback to display the cursor in a pane
|
||||||
|
@ -674,7 +680,7 @@ class Diffuse(Gtk.Window):
|
||||||
self.footers[f].setFormat(fmt)
|
self.footers[f].setFormat(fmt)
|
||||||
|
|
||||||
def __init__(self, rc_dir):
|
def __init__(self, rc_dir):
|
||||||
Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL)
|
super().__init__(type=Gtk.WindowType.TOPLEVEL)
|
||||||
|
|
||||||
self.prefs = Preferences(os.path.join(rc_dir, 'prefs'))
|
self.prefs = Preferences(os.path.join(rc_dir, 'prefs'))
|
||||||
# number of created viewers (used to label some tabs)
|
# number of created viewers (used to label some tabs)
|
||||||
|
@ -702,8 +708,8 @@ class Diffuse(Gtk.Window):
|
||||||
self.connect('window-state-event', self.window_state_cb)
|
self.connect('window-state-event', self.window_state_cb)
|
||||||
|
|
||||||
# search history is application wide
|
# search history is application wide
|
||||||
self.search_pattern = None
|
self.search_pattern: Optional[str] = None
|
||||||
self.search_history = []
|
self.search_history: List[str] = []
|
||||||
|
|
||||||
self.connect('delete-event', self.delete_cb)
|
self.connect('delete-event', self.delete_cb)
|
||||||
accel_group = Gtk.AccelGroup()
|
accel_group = Gtk.AccelGroup()
|
||||||
|
@ -968,7 +974,7 @@ class Diffuse(Gtk.Window):
|
||||||
)
|
)
|
||||||
|
|
||||||
# load state information that should persist across sessions
|
# load state information that should persist across sessions
|
||||||
def loadState(self, statepath):
|
def loadState(self, statepath: str) -> None:
|
||||||
if os.path.isfile(statepath):
|
if os.path.isfile(statepath):
|
||||||
try:
|
try:
|
||||||
f = open(statepath, 'r')
|
f = open(statepath, 'r')
|
||||||
|
@ -998,7 +1004,7 @@ class Diffuse(Gtk.Window):
|
||||||
self.maximize()
|
self.maximize()
|
||||||
|
|
||||||
# save state information that should persist across sessions
|
# save state information that should persist across sessions
|
||||||
def saveState(self, statepath):
|
def saveState(self, statepath: str) -> None:
|
||||||
try:
|
try:
|
||||||
ss = []
|
ss = []
|
||||||
for k, v in self.bool_state.items():
|
for k, v in self.bool_state.items():
|
||||||
|
@ -1025,7 +1031,7 @@ class Diffuse(Gtk.Window):
|
||||||
|
|
||||||
# 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
|
||||||
# given a chance to save any modified files before this method completes.
|
# given a chance to save any modified files before this method completes.
|
||||||
def confirmCloseViewers(self, viewers):
|
def confirmCloseViewers(self, viewers: List[FileDiffViewer]) -> bool:
|
||||||
# make a list of modified files
|
# make a list of modified files
|
||||||
model = Gtk.ListStore.new([
|
model = Gtk.ListStore.new([
|
||||||
GObject.TYPE_BOOLEAN,
|
GObject.TYPE_BOOLEAN,
|
||||||
|
@ -1144,12 +1150,12 @@ class Diffuse(Gtk.Window):
|
||||||
menu.popup(None, None, None, event.button, event.time)
|
menu.popup(None, None, None, event.button, event.time)
|
||||||
|
|
||||||
# update window's title
|
# update window's title
|
||||||
def updateTitle(self, viewer):
|
def updateTitle(self, viewer: FileDiffViewer) -> None:
|
||||||
title = self.notebook.get_tab_label(viewer).get_text()
|
title = self.notebook.get_tab_label(viewer).get_text()
|
||||||
self.set_title(f'{title} - {constants.APP_NAME}')
|
self.set_title(f'{title} - {constants.APP_NAME}')
|
||||||
|
|
||||||
# update the message in the status bar
|
# update the message in the status bar
|
||||||
def setStatus(self, s):
|
def setStatus(self, s: Optional[str]) -> None:
|
||||||
sb = self.statusbar
|
sb = self.statusbar
|
||||||
context = sb.get_context_id('Message')
|
context = sb.get_context_id('Message')
|
||||||
sb.pop(context)
|
sb.pop(context)
|
||||||
|
@ -1358,7 +1364,7 @@ class Diffuse(Gtk.Window):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# returns the currently focused viewer
|
# returns the currently focused viewer
|
||||||
def getCurrentViewer(self) -> Optional[Gtk.Widget]:
|
def getCurrentViewer(self) -> FileDiffViewer:
|
||||||
return self.notebook.get_nth_page(self.notebook.get_current_page())
|
return self.notebook.get_nth_page(self.notebook.get_current_page())
|
||||||
|
|
||||||
# callback for the open file menu item
|
# callback for the open file menu item
|
||||||
|
@ -1504,7 +1510,7 @@ class Diffuse(Gtk.Window):
|
||||||
|
|
||||||
# request search parameters if force=True and then perform a search in the
|
# request search parameters if force=True and then perform a search in the
|
||||||
# current viewer pane
|
# current viewer pane
|
||||||
def find(self, force, reverse):
|
def find(self, force: bool, reverse: bool) -> None:
|
||||||
viewer = self.getCurrentViewer()
|
viewer = self.getCurrentViewer()
|
||||||
if force or self.search_pattern is None:
|
if force or self.search_pattern is None:
|
||||||
# construct search dialog
|
# construct search dialog
|
||||||
|
|
|
@ -21,9 +21,9 @@ import difflib
|
||||||
import os
|
import os
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
from enum import IntFlag
|
from enum import Flag, IntFlag, auto
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Callable, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from diffuse import utils
|
from diffuse import utils
|
||||||
from diffuse.resources import theResources
|
from diffuse.resources import theResources
|
||||||
|
@ -38,14 +38,12 @@ gi.require_version('PangoCairo', '1.0')
|
||||||
from gi.repository import GObject, Gdk, Gtk, Pango, PangoCairo # type: ignore # noqa: E402
|
from gi.repository import GObject, Gdk, Gtk, Pango, PangoCairo # type: ignore # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
# mapping to column width of a character (tab will never be in this map)
|
|
||||||
_char_width_cache: Dict[str, int] = {}
|
|
||||||
|
|
||||||
# the file diff viewer is always in one of these modes defining the cursor,
|
# the file diff viewer is always in one of these modes defining the cursor,
|
||||||
# and hotkey behavior
|
# and hotkey behavior
|
||||||
LINE_MODE = 0
|
class EditMode(Flag):
|
||||||
CHAR_MODE = 1
|
LINE = auto()
|
||||||
ALIGN_MODE = 2
|
CHAR = auto()
|
||||||
|
ALIGN = auto()
|
||||||
|
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -198,10 +196,14 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
if n < 2:
|
if n < 2:
|
||||||
raise ValueError('Invalid number of panes')
|
raise ValueError('Invalid number of panes')
|
||||||
|
|
||||||
Gtk.Grid.__init__(self)
|
super().__init__()
|
||||||
|
|
||||||
|
# mapping to column width of a character (tab will never be in this map)
|
||||||
|
self._char_width_cache: Dict[str, int] = {}
|
||||||
|
|
||||||
self.set_can_focus(True)
|
self.set_can_focus(True)
|
||||||
self.prefs = prefs
|
self.prefs = prefs
|
||||||
self.string_width_cache = {}
|
self.string_width_cache: Dict[str, Optional[int]] = {}
|
||||||
self.options = {}
|
self.options = {}
|
||||||
|
|
||||||
# diff blocks
|
# diff blocks
|
||||||
|
@ -217,7 +219,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
self.diffmap_cache = None
|
self.diffmap_cache = None
|
||||||
|
|
||||||
# editing mode
|
# editing mode
|
||||||
self.mode = LINE_MODE
|
self.mode = EditMode.LINE
|
||||||
self.current_pane = 1
|
self.current_pane = 1
|
||||||
self.current_line = 0
|
self.current_line = 0
|
||||||
self.current_char = 0
|
self.current_char = 0
|
||||||
|
@ -228,7 +230,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
self.cursor_column = -1
|
self.cursor_column = -1
|
||||||
|
|
||||||
# keybindings
|
# keybindings
|
||||||
self._line_mode_actions = {
|
self._line_mode_actions: Dict[str, Callable] = {
|
||||||
'enter_align_mode': self._line_mode_enter_align_mode,
|
'enter_align_mode': self._line_mode_enter_align_mode,
|
||||||
'enter_character_mode': self.setCharMode,
|
'enter_character_mode': self.setCharMode,
|
||||||
'first_line': self._first_line,
|
'first_line': self._first_line,
|
||||||
|
@ -261,7 +263,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
'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: Dict[str, Callable] = {
|
||||||
'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,
|
||||||
'first_line': self._first_line,
|
'first_line': self._first_line,
|
||||||
|
@ -274,10 +276,10 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
'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: Dict[str, Callable] = {
|
||||||
'enter_line_mode': self.setLineMode
|
'enter_line_mode': self.setLineMode
|
||||||
}
|
}
|
||||||
self._button_actions = {
|
self._button_actions: Dict[str, Callable] = {
|
||||||
'undo': self.undo,
|
'undo': self.undo,
|
||||||
'redo': self.redo,
|
'redo': self.redo,
|
||||||
'cut': self.cut,
|
'cut': self.cut,
|
||||||
|
@ -315,7 +317,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
}
|
}
|
||||||
|
|
||||||
# create panes
|
# create panes
|
||||||
self.dareas = []
|
self.dareas: List[Gtk.DrawingArea] = []
|
||||||
self.panes: List[FileDiffViewerBase.Pane] = []
|
self.panes: List[FileDiffViewerBase.Pane] = []
|
||||||
self.hadj = Gtk.Adjustment.new(0, 0, 0, 0, 0, 0)
|
self.hadj = Gtk.Adjustment.new(0, 0, 0, 0, 0, 0)
|
||||||
self.vadj = Gtk.Adjustment.new(0, 0, 0, 0, 0, 0)
|
self.vadj = Gtk.Adjustment.new(0, 0, 0, 0, 0, 0)
|
||||||
|
@ -414,7 +416,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
col = 0
|
col = 0
|
||||||
for c in s:
|
for c in s:
|
||||||
try:
|
try:
|
||||||
w = _char_width_cache[c]
|
w = self._char_width_cache[c]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
v = ord(c)
|
v = ord(c)
|
||||||
if v < 32:
|
if v < 32:
|
||||||
|
@ -423,23 +425,23 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
w = tab_width - col % tab_width
|
w = tab_width - col % tab_width
|
||||||
elif c == '\n':
|
elif c == '\n':
|
||||||
w = 1
|
w = 1
|
||||||
_char_width_cache[c] = w
|
self._char_width_cache[c] = w
|
||||||
else:
|
else:
|
||||||
w = 2
|
w = 2
|
||||||
_char_width_cache[c] = w
|
self._char_width_cache[c] = w
|
||||||
else:
|
else:
|
||||||
if unicodedata.east_asian_width(c) in 'WF':
|
if unicodedata.east_asian_width(c) in 'WF':
|
||||||
w = 2
|
w = 2
|
||||||
else:
|
else:
|
||||||
w = 1
|
w = 1
|
||||||
_char_width_cache[c] = w
|
self._char_width_cache[c] = w
|
||||||
col += w
|
col += w
|
||||||
return col
|
return col
|
||||||
|
|
||||||
# returns the 'column width' for a single character created at column 'i'
|
# returns the 'column width' for a single character created at column 'i'
|
||||||
def characterWidth(self, i: int, c: str) -> int:
|
def characterWidth(self, i: int, c: str) -> int:
|
||||||
try:
|
try:
|
||||||
return _char_width_cache[c]
|
return self._char_width_cache[c]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
v = ord(c)
|
v = ord(c)
|
||||||
if v < 32:
|
if v < 32:
|
||||||
|
@ -454,7 +456,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
w = 2
|
w = 2
|
||||||
else:
|
else:
|
||||||
w = 1
|
w = 1
|
||||||
_char_width_cache[c] = w
|
self._char_width_cache[c] = w
|
||||||
return w
|
return w
|
||||||
|
|
||||||
# translates a string into an array of the printable representation for
|
# translates a string into an array of the printable representation for
|
||||||
|
@ -493,32 +495,32 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
col += self.characterWidth(col, c)
|
col += self.characterWidth(col, c)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# changes the viewer's mode to LINE_MODE
|
# changes the viewer's mode to EditMode.LINE
|
||||||
def setLineMode(self) -> None:
|
def setLineMode(self) -> None:
|
||||||
if self.mode != LINE_MODE:
|
if self.mode != EditMode.LINE:
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
self._im_focus_out()
|
self._im_focus_out()
|
||||||
self.im_context.reset()
|
self.im_context.reset()
|
||||||
self._im_set_preedit(None)
|
self._im_set_preedit(None)
|
||||||
self.current_char = 0
|
self.current_char = 0
|
||||||
self.selection_char = 0
|
self.selection_char = 0
|
||||||
self.dareas[self.current_pane].queue_draw()
|
self.dareas[self.current_pane].queue_draw()
|
||||||
elif self.mode == ALIGN_MODE:
|
elif self.mode == EditMode.ALIGN:
|
||||||
self.dareas[self.align_pane].queue_draw()
|
self.dareas[self.align_pane].queue_draw()
|
||||||
self.dareas[self.current_pane].queue_draw()
|
self.dareas[self.current_pane].queue_draw()
|
||||||
self.align_pane = 0
|
self.align_pane = 0
|
||||||
self.align_line = 0
|
self.align_line = 0
|
||||||
self.mode = LINE_MODE
|
self.mode = EditMode.LINE
|
||||||
self.emit('cursor_changed')
|
self.emit('cursor_changed')
|
||||||
self.emit('mode_changed')
|
self.emit('mode_changed')
|
||||||
|
|
||||||
# changes the viewer's mode to CHAR_MODE
|
# changes the viewer's mode to CHAR_MODE
|
||||||
def setCharMode(self) -> None:
|
def setCharMode(self) -> None:
|
||||||
if self.mode != CHAR_MODE:
|
if self.mode != EditMode.CHAR:
|
||||||
if self.mode == LINE_MODE:
|
if self.mode == EditMode.LINE:
|
||||||
self.cursor_column = -1
|
self.cursor_column = -1
|
||||||
self.setCurrentChar(self.current_line, 0)
|
self.setCurrentChar(self.current_line, 0)
|
||||||
elif self.mode == ALIGN_MODE:
|
elif self.mode == EditMode.ALIGN:
|
||||||
self.dareas[self.align_pane].queue_draw()
|
self.dareas[self.align_pane].queue_draw()
|
||||||
self.cursor_column = -1
|
self.cursor_column = -1
|
||||||
self.align_pane = 0
|
self.align_pane = 0
|
||||||
|
@ -526,7 +528,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
self.setCurrentChar(self.current_line, 0)
|
self.setCurrentChar(self.current_line, 0)
|
||||||
self._im_focus_in()
|
self._im_focus_in()
|
||||||
self.im_context.reset()
|
self.im_context.reset()
|
||||||
self.mode = CHAR_MODE
|
self.mode = EditMode.CHAR
|
||||||
self.emit('cursor_changed')
|
self.emit('cursor_changed')
|
||||||
self.emit('mode_changed')
|
self.emit('mode_changed')
|
||||||
|
|
||||||
|
@ -584,10 +586,10 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# 'undo' action
|
# 'undo' action
|
||||||
def undo(self) -> None:
|
def undo(self) -> None:
|
||||||
self.undoblock, old_block = None, self.undoblock
|
self.undoblock, old_block = None, self.undoblock
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# avoid implicit preedit commit when an undo changes the mode
|
# avoid implicit preedit commit when an undo changes the mode
|
||||||
self.im_context.reset()
|
self.im_context.reset()
|
||||||
if self.mode in (LINE_MODE, CHAR_MODE):
|
if self.mode in (EditMode.LINE, EditMode.CHAR):
|
||||||
if len(self.undos) > 0:
|
if len(self.undos) > 0:
|
||||||
# move the block to the redo stack
|
# move the block to the redo stack
|
||||||
block = self.undos.pop()
|
block = self.undos.pop()
|
||||||
|
@ -600,8 +602,8 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# 'redo' action
|
# 'redo' action
|
||||||
def redo(self) -> None:
|
def redo(self) -> None:
|
||||||
self.undoblock, old_block = None, self.undoblock
|
self.undoblock, old_block = None, self.undoblock
|
||||||
if self.mode in (LINE_MODE, CHAR_MODE):
|
if self.mode in (EditMode.LINE, EditMode.CHAR):
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# avoid implicit preedit commit when an redo changes the mode
|
# avoid implicit preedit commit when an redo changes the mode
|
||||||
self.im_context.reset()
|
self.im_context.reset()
|
||||||
if len(self.redos) > 0:
|
if len(self.redos) > 0:
|
||||||
|
@ -657,10 +659,10 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
text.append(line.modified_text)
|
text.append(line.modified_text)
|
||||||
for s in text:
|
for s in text:
|
||||||
if s is not None:
|
if s is not None:
|
||||||
w = string_width_cache.get(s, None)
|
swc = string_width_cache.get(s, None)
|
||||||
if w is None:
|
if swc is None:
|
||||||
string_width_cache[s] = w = stringWidth(s)
|
string_width_cache[s] = swc = stringWidth(s)
|
||||||
pane.line_lengths = max(pane.line_lengths, digit_width * w)
|
pane.line_lengths = max(pane.line_lengths, digit_width * swc)
|
||||||
# compute the maximum extents
|
# compute the maximum extents
|
||||||
num_lines, line_lengths = 0, 0
|
num_lines, line_lengths = 0, 0
|
||||||
for pane in self.panes:
|
for pane in self.panes:
|
||||||
|
@ -1282,7 +1284,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
pane = self.panes[f]
|
pane = self.panes[f]
|
||||||
nlines = len(pane.lines)
|
nlines = len(pane.lines)
|
||||||
line0, line1 = self.selection_line, self.current_line
|
line0, line1 = self.selection_line, self.current_line
|
||||||
if self.mode == LINE_MODE:
|
if self.mode == EditMode.LINE:
|
||||||
col0, col1 = 0, 0
|
col0, col1 = 0, 0
|
||||||
if line1 < line0:
|
if line1 < line0:
|
||||||
line0, line1 = line1, line0
|
line0, line1 = line1, line0
|
||||||
|
@ -1349,7 +1351,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
for i in range(delta):
|
for i in range(delta):
|
||||||
self.updateText(f, line0 + n_need + i, None)
|
self.updateText(f, line0 + n_need + i, None)
|
||||||
# update selection
|
# update selection
|
||||||
if self.mode == LINE_MODE:
|
if self.mode == EditMode.LINE:
|
||||||
self.setCurrentLine(f, line0 + max(n_need, 1) - 1, line0)
|
self.setCurrentLine(f, line0 + max(n_need, 1) - 1, line0)
|
||||||
else:
|
else:
|
||||||
self.setCurrentChar(cur_line, lastcol)
|
self.setCurrentChar(cur_line, lastcol)
|
||||||
|
@ -1523,7 +1525,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
self.selection_line = selection_line
|
self.selection_line = selection_line
|
||||||
self.selection_char = selection_char
|
self.selection_char = selection_char
|
||||||
self.cursor_column = cursor_column
|
self.cursor_column = cursor_column
|
||||||
if mode == CHAR_MODE:
|
if mode == EditMode.CHAR:
|
||||||
self.setCurrentChar(self.current_line, self.current_char, True)
|
self.setCurrentChar(self.current_line, self.current_char, True)
|
||||||
else:
|
else:
|
||||||
self.setCurrentLine(self.current_pane, self.current_line, self.selection_line)
|
self.setCurrentLine(self.current_pane, self.current_line, self.selection_line)
|
||||||
|
@ -1555,7 +1557,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
elif upper > v + ps:
|
elif upper > v + ps:
|
||||||
vadj.set_value(upper - ps)
|
vadj.set_value(upper - ps)
|
||||||
|
|
||||||
# change the current selection in LINE_MODE
|
# change the current selection in EditMode.LINE
|
||||||
# use extend=True to extend the selection
|
# use extend=True to extend the selection
|
||||||
def setCurrentLine(self, f: int, i: int, selection: Optional[int] = None) -> None:
|
def setCurrentLine(self, f: int, i: int, selection: Optional[int] = None) -> None:
|
||||||
# remember old cursor position so we can just redraw what is necessary
|
# remember old cursor position so we can just redraw what is necessary
|
||||||
|
@ -1584,7 +1586,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# returns True if the line has preedit text
|
# returns True if the line has preedit text
|
||||||
def hasPreedit(self, f: int, i: int) -> bool:
|
def hasPreedit(self, f: int, i: int) -> bool:
|
||||||
return (
|
return (
|
||||||
self.mode == CHAR_MODE and
|
self.mode == EditMode.CHAR and
|
||||||
self.current_pane == f and
|
self.current_pane == f and
|
||||||
self.current_line == i and
|
self.current_line == i and
|
||||||
self.im_preedit is not None
|
self.im_preedit is not None
|
||||||
|
@ -1602,7 +1604,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# inform input method about cursor motion
|
# inform input method about cursor motion
|
||||||
def _cursor_position_changed(self, recompute):
|
def _cursor_position_changed(self, recompute):
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# update input method
|
# update input method
|
||||||
h = self.font_height
|
h = self.font_height
|
||||||
if recompute:
|
if recompute:
|
||||||
|
@ -1698,7 +1700,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
f = self.current_pane
|
f = self.current_pane
|
||||||
start, end = self.selection_line, self.current_line
|
start, end = self.selection_line, self.current_line
|
||||||
# find extents of selection
|
# find extents of selection
|
||||||
if self.mode == LINE_MODE:
|
if self.mode == EditMode.LINE:
|
||||||
if end < start:
|
if end < start:
|
||||||
start, end = end, start
|
start, end = end, start
|
||||||
end += 1
|
end += 1
|
||||||
|
@ -1722,11 +1724,11 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# expands the selection to include everything
|
# expands the selection to include everything
|
||||||
def select_all(self) -> None:
|
def select_all(self) -> None:
|
||||||
if self.mode in (LINE_MODE, CHAR_MODE):
|
if self.mode in (EditMode.LINE, EditMode.CHAR):
|
||||||
f = self.current_pane
|
f = self.current_pane
|
||||||
self.selection_line = 0
|
self.selection_line = 0
|
||||||
self.current_line = len(self.panes[f].lines)
|
self.current_line = len(self.panes[f].lines)
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
self.selection_char = 0
|
self.selection_char = 0
|
||||||
self.current_char = 0
|
self.current_char = 0
|
||||||
self.dareas[f].queue_draw()
|
self.dareas[f].queue_draw()
|
||||||
|
@ -1756,7 +1758,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
if y < 0:
|
if y < 0:
|
||||||
x, y = -1, 0
|
x, y = -1, 0
|
||||||
i = min(y // self.font_height, len(self.panes[f].lines))
|
i = min(y // self.font_height, len(self.panes[f].lines))
|
||||||
if self.mode == CHAR_MODE and f == self.current_pane:
|
if self.mode == EditMode.CHAR and f == self.current_pane:
|
||||||
text = utils.strip_eol(self.getLineText(f, i))
|
text = utils.strip_eol(self.getLineText(f, i))
|
||||||
j = self._getPickedCharacter(text, x, True)
|
j = self._getPickedCharacter(text, x, True)
|
||||||
if extend:
|
if extend:
|
||||||
|
@ -1765,9 +1767,9 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
si, sj = None, None
|
si, sj = None, None
|
||||||
self.setCurrentChar(i, j, si, sj)
|
self.setCurrentChar(i, j, si, sj)
|
||||||
else:
|
else:
|
||||||
if self.mode == ALIGN_MODE:
|
if self.mode == EditMode.ALIGN:
|
||||||
extend = False
|
extend = False
|
||||||
elif self.mode == CHAR_MODE:
|
elif self.mode == EditMode.CHAR:
|
||||||
self.setLineMode()
|
self.setLineMode()
|
||||||
if extend and f == self.current_pane:
|
if extend and f == self.current_pane:
|
||||||
selection = self.selection_line
|
selection = self.selection_line
|
||||||
|
@ -1786,17 +1788,17 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# left mouse button
|
# left mouse button
|
||||||
if event.type == Gdk.EventType._2BUTTON_PRESS:
|
if event.type == Gdk.EventType._2BUTTON_PRESS:
|
||||||
# double click
|
# double click
|
||||||
if self.mode == ALIGN_MODE:
|
if self.mode == EditMode.ALIGN:
|
||||||
self.setLineMode()
|
self.setLineMode()
|
||||||
if self.mode == LINE_MODE:
|
if self.mode == EditMode.LINE:
|
||||||
# change to CHAR_MODE
|
# change to CHAR_MODE
|
||||||
self.setCurrentLine(f, i)
|
self.setCurrentLine(f, i)
|
||||||
# silently switch mode so the viewer does not scroll yet.
|
# silently switch mode so the viewer does not scroll yet.
|
||||||
self.mode = CHAR_MODE
|
self.mode = EditMode.CHAR
|
||||||
self._im_focus_in()
|
self._im_focus_in()
|
||||||
self.button_press(f, x, y, False)
|
self.button_press(f, x, y, False)
|
||||||
self.emit('mode_changed')
|
self.emit('mode_changed')
|
||||||
elif self.mode == CHAR_MODE and self.current_pane == f:
|
elif self.mode == EditMode.CHAR and self.current_pane == f:
|
||||||
# select word
|
# select word
|
||||||
text = utils.strip_eol(self.getLineText(f, i))
|
text = utils.strip_eol(self.getLineText(f, i))
|
||||||
if text is not None:
|
if text is not None:
|
||||||
|
@ -1812,7 +1814,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
self.setCurrentChar(i, j, i, k)
|
self.setCurrentChar(i, j, i, k)
|
||||||
elif event.type == Gdk.EventType._3BUTTON_PRESS:
|
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 == EditMode.CHAR and self.current_pane == f:
|
||||||
i2 = min(i + 1, nlines)
|
i2 = min(i + 1, nlines)
|
||||||
self.setCurrentChar(i2, 0, i, 0)
|
self.setCurrentChar(i2, 0, i, 0)
|
||||||
else:
|
else:
|
||||||
|
@ -1822,7 +1824,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
self.button_press(f, x, y, extend)
|
self.button_press(f, x, y, extend)
|
||||||
elif event.button == 2:
|
elif event.button == 2:
|
||||||
# middle mouse button, paste primary selection
|
# middle mouse button, paste primary selection
|
||||||
if self.mode == CHAR_MODE and f == self.current_pane:
|
if self.mode == EditMode.CHAR and f == self.current_pane:
|
||||||
self.button_press(f, x, y, False)
|
self.button_press(f, x, y, False)
|
||||||
self.openUndoBlock()
|
self.openUndoBlock()
|
||||||
Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY).request_text(
|
Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY).request_text(
|
||||||
|
@ -1832,11 +1834,11 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
elif event.button == 3:
|
elif event.button == 3:
|
||||||
# right mouse button, raise context sensitive menu
|
# right mouse button, raise context sensitive menu
|
||||||
can_align = (
|
can_align = (
|
||||||
self.mode == LINE_MODE and
|
self.mode == EditMode.LINE and
|
||||||
(f in (self.current_pane + 1, f == self.current_pane - 1)))
|
(f in (self.current_pane + 1, f == self.current_pane - 1)))
|
||||||
can_isolate = self.mode == LINE_MODE and f == self.current_pane
|
can_isolate = self.mode == EditMode.LINE and f == self.current_pane
|
||||||
can_merge = self.mode == LINE_MODE and f != self.current_pane
|
can_merge = self.mode == EditMode.LINE and f != self.current_pane
|
||||||
can_select = self.mode in (LINE_MODE, CHAR_MODE) and f == self.current_pane
|
can_select = self.mode in (EditMode.LINE, EditMode.CHAR) and f == self.current_pane
|
||||||
can_swap = (f != self.current_pane)
|
can_swap = (f != self.current_pane)
|
||||||
|
|
||||||
menu = createMenu([
|
menu = createMenu([
|
||||||
|
@ -2136,14 +2138,14 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
preedit_bg_colour = (colour * alpha).over(preedit_bg_colour)
|
preedit_bg_colour = (colour * alpha).over(preedit_bg_colour)
|
||||||
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
|
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
|
||||||
cr.paint()
|
cr.paint()
|
||||||
if self.mode == ALIGN_MODE:
|
if self.mode == EditMode.ALIGN:
|
||||||
# draw align
|
# draw align
|
||||||
if self.align_pane == f and self.align_line == i:
|
if self.align_pane == f and self.align_line == i:
|
||||||
colour = theResources.getColour('alignment')
|
colour = theResources.getColour('alignment')
|
||||||
alpha = theResources.getFloat('alignment_opacity')
|
alpha = theResources.getFloat('alignment_opacity')
|
||||||
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
|
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
|
||||||
cr.paint()
|
cr.paint()
|
||||||
elif self.mode == LINE_MODE:
|
elif self.mode == EditMode.LINE:
|
||||||
# draw line selection
|
# draw line selection
|
||||||
if self.current_pane == f:
|
if self.current_pane == f:
|
||||||
start, end = self.selection_line, self.current_line
|
start, end = self.selection_line, self.current_line
|
||||||
|
@ -2154,7 +2156,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
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)
|
||||||
cr.paint()
|
cr.paint()
|
||||||
elif self.mode == CHAR_MODE:
|
elif self.mode == EditMode.CHAR:
|
||||||
# draw char selection
|
# draw char selection
|
||||||
if self.current_pane == f and text is not None:
|
if self.current_pane == f and text is not None:
|
||||||
start, end = self.selection_line, self.current_line
|
start, end = self.selection_line, self.current_line
|
||||||
|
@ -2286,7 +2288,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
if self.current_pane == f and self.current_line == i:
|
if self.current_pane == f and self.current_line == i:
|
||||||
# draw the cursor and preedit text
|
# draw the cursor and preedit text
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
x_pos = x_start + _pixels(self._get_cursor_x_offset())
|
x_pos = x_start + _pixels(self._get_cursor_x_offset())
|
||||||
if has_preedit:
|
if has_preedit:
|
||||||
# we have preedit text
|
# we have preedit text
|
||||||
|
@ -2312,7 +2314,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
cr.move_to(x_pos + 0.5, y_start)
|
cr.move_to(x_pos + 0.5, y_start)
|
||||||
cr.rel_line_to(0, h)
|
cr.rel_line_to(0, h)
|
||||||
cr.stroke()
|
cr.stroke()
|
||||||
elif self.mode in (LINE_MODE, ALIGN_MODE):
|
elif self.mode in (EditMode.LINE, EditMode.ALIGN):
|
||||||
# draw the line editing cursor
|
# draw the line editing cursor
|
||||||
colour = theResources.getColour('cursor')
|
colour = theResources.getColour('cursor')
|
||||||
cr.set_source_rgb(colour.red, colour.green, colour.blue)
|
cr.set_source_rgb(colour.red, colour.green, colour.blue)
|
||||||
|
@ -2485,11 +2487,11 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# 'enter_align_mode' keybinding action
|
# 'enter_align_mode' keybinding action
|
||||||
def _line_mode_enter_align_mode(self):
|
def _line_mode_enter_align_mode(self):
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
self._im_focus_out()
|
self._im_focus_out()
|
||||||
self.im_context.reset()
|
self.im_context.reset()
|
||||||
self._im_set_preedit(None)
|
self._im_set_preedit(None)
|
||||||
self.mode = ALIGN_MODE
|
self.mode = EditMode.ALIGN
|
||||||
self.selection_line = self.current_line
|
self.selection_line = self.current_line
|
||||||
self.align_pane = self.current_pane
|
self.align_pane = self.current_pane
|
||||||
self.align_line = self.current_line
|
self.align_line = self.current_line
|
||||||
|
@ -2597,7 +2599,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# input method callback for committed text
|
# input method callback for committed text
|
||||||
def im_commit_cb(self, im, s):
|
def im_commit_cb(self, im, s):
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
self.openUndoBlock()
|
self.openUndoBlock()
|
||||||
self.replaceText(s)
|
self.replaceText(s)
|
||||||
self.closeUndoBlock()
|
self.closeUndoBlock()
|
||||||
|
@ -2605,7 +2607,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# update the cached preedit text
|
# update the cached preedit text
|
||||||
def _im_set_preedit(self, p):
|
def _im_set_preedit(self, p):
|
||||||
self.im_preedit = p
|
self.im_preedit = p
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
f, i = self.current_pane, self.current_line
|
f, i = self.current_pane, self.current_line
|
||||||
self._queue_draw_lines(f, i)
|
self._queue_draw_lines(f, i)
|
||||||
if f > 0:
|
if f > 0:
|
||||||
|
@ -2616,7 +2618,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# queue a redraw for location of preedit text
|
# queue a redraw for location of preedit text
|
||||||
def im_preedit_changed_cb(self, im):
|
def im_preedit_changed_cb(self, im):
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
s, a, c = self.im_context.get_preedit_string()
|
s, a, c = self.im_context.get_preedit_string()
|
||||||
if len(s) > 0:
|
if len(s) > 0:
|
||||||
# we have preedit text, draw that instead
|
# we have preedit text, draw that instead
|
||||||
|
@ -2628,7 +2630,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# callback to respond to retrieve_surrounding signals from input methods
|
# callback to respond to retrieve_surrounding signals from input methods
|
||||||
def im_retrieve_surrounding_cb(self, im):
|
def im_retrieve_surrounding_cb(self, im):
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# notify input method of text surrounding the cursor
|
# notify input method of text surrounding the cursor
|
||||||
s = utils.null_to_empty(self.getLineText(self.current_pane, self.current_line))
|
s = utils.null_to_empty(self.getLineText(self.current_pane, self.current_line))
|
||||||
im.set_surrounding(s, len(s), self.current_char)
|
im.set_surrounding(s, len(s), self.current_char)
|
||||||
|
@ -2636,13 +2638,13 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# callback for 'focus_in_event'
|
# callback for 'focus_in_event'
|
||||||
def focus_in_cb(self, widget, event):
|
def focus_in_cb(self, widget, event):
|
||||||
self.has_focus = True
|
self.has_focus = True
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# notify the input method of the focus change
|
# notify the input method of the focus change
|
||||||
self._im_focus_in()
|
self._im_focus_in()
|
||||||
|
|
||||||
# callback for 'focus_out_event'
|
# callback for 'focus_out_event'
|
||||||
def focus_out_cb(self, widget, event):
|
def focus_out_cb(self, widget, event):
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# notify the input method of the focus change
|
# notify the input method of the focus change
|
||||||
self._im_focus_out()
|
self._im_focus_out()
|
||||||
self.has_focus = False
|
self.has_focus = False
|
||||||
|
@ -2650,7 +2652,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# callback for keyboard events
|
# callback for keyboard events
|
||||||
# only keypresses that are not handled by menu item accelerators reach here
|
# only keypresses that are not handled by menu item accelerators reach here
|
||||||
def key_press_cb(self, widget, event):
|
def key_press_cb(self, widget, event):
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# update input method
|
# update input method
|
||||||
if self.im_context.filter_keypress(event):
|
if self.im_context.filter_keypress(event):
|
||||||
return True
|
return True
|
||||||
|
@ -2660,13 +2662,13 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
if event.state & Gdk.ModifierType.LOCK_MASK:
|
if event.state & Gdk.ModifierType.LOCK_MASK:
|
||||||
mask ^= Gdk.ModifierType.SHIFT_MASK
|
mask ^= Gdk.ModifierType.SHIFT_MASK
|
||||||
self.openUndoBlock()
|
self.openUndoBlock()
|
||||||
if self.mode == LINE_MODE:
|
if self.mode == EditMode.LINE:
|
||||||
# check if the keyval matches a line mode action
|
# check if the keyval matches a line mode action
|
||||||
action = theResources.getActionForKey('line_mode', event.keyval, mask)
|
action = theResources.getActionForKey('line_mode', event.keyval, mask)
|
||||||
if action in self._line_mode_actions:
|
if action in self._line_mode_actions:
|
||||||
self._line_mode_actions[action]()
|
self._line_mode_actions[action]()
|
||||||
retval = True
|
retval = True
|
||||||
elif self.mode == CHAR_MODE:
|
elif self.mode == EditMode.CHAR:
|
||||||
f = self.current_pane
|
f = self.current_pane
|
||||||
if event.state & Gdk.ModifierType.SHIFT_MASK:
|
if event.state & Gdk.ModifierType.SHIFT_MASK:
|
||||||
si, sj = self.selection_line, self.selection_char
|
si, sj = self.selection_line, self.selection_char
|
||||||
|
@ -2918,7 +2920,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# handle all other printable characters
|
# handle all other printable characters
|
||||||
elif len(event.string) > 0:
|
elif len(event.string) > 0:
|
||||||
self.replaceText(event.string)
|
self.replaceText(event.string)
|
||||||
elif self.mode == ALIGN_MODE:
|
elif self.mode == EditMode.ALIGN:
|
||||||
# check if the keyval matches an align mode action
|
# check if the keyval matches an align mode action
|
||||||
action = theResources.getActionForKey('align_mode', event.keyval, mask)
|
action = theResources.getActionForKey('align_mode', event.keyval, mask)
|
||||||
if action in self._align_mode_actions:
|
if action in self._align_mode_actions:
|
||||||
|
@ -2929,18 +2931,18 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# 'copy' action
|
# 'copy' action
|
||||||
def copy(self) -> None:
|
def copy(self) -> None:
|
||||||
if self.mode in (LINE_MODE, CHAR_MODE):
|
if self.mode in (EditMode.LINE, EditMode.CHAR):
|
||||||
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) -> None:
|
def cut(self) -> None:
|
||||||
if self.mode in (LINE_MODE, CHAR_MODE):
|
if self.mode in (EditMode.LINE, EditMode.CHAR):
|
||||||
self.copy()
|
self.copy()
|
||||||
self.replaceText('')
|
self.replaceText('')
|
||||||
|
|
||||||
# callback used when receiving clipboard text
|
# callback used when receiving clipboard text
|
||||||
def receive_clipboard_text_cb(self, clipboard, text, data):
|
def receive_clipboard_text_cb(self, clipboard, text, data):
|
||||||
if self.mode in (LINE_MODE, CHAR_MODE):
|
if self.mode in (EditMode.LINE, EditMode.CHAR):
|
||||||
# there is no guarantee this will be called before finishing
|
# there is no guarantee this will be called before finishing
|
||||||
# Gtk.Clipboard.get so we may need to create our own undo block
|
# Gtk.Clipboard.get so we may need to create our own undo block
|
||||||
needs_block = (self.undoblock is None)
|
needs_block = (self.undoblock is None)
|
||||||
|
@ -2977,7 +2979,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# 'dismiss_all_edits' action
|
# 'dismiss_all_edits' action
|
||||||
def dismiss_all_edits(self) -> None:
|
def dismiss_all_edits(self) -> None:
|
||||||
if self.mode in (LINE_MODE, CHAR_MODE):
|
if self.mode in (EditMode.LINE, EditMode.CHAR):
|
||||||
self.bakeEdits(self.current_pane)
|
self.bakeEdits(self.current_pane)
|
||||||
|
|
||||||
# callback for find menu item
|
# callback for find menu item
|
||||||
|
@ -3268,7 +3270,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# swap the contents of two panes
|
# swap the contents of two panes
|
||||||
def swap_panes(self, f_dst: int, f_src: int) -> None:
|
def swap_panes(self, f_dst: int, f_src: int) -> None:
|
||||||
if 0 <= f_dst < len(self.panes):
|
if 0 <= f_dst < len(self.panes):
|
||||||
if self.mode == ALIGN_MODE:
|
if self.mode == EditMode.ALIGN:
|
||||||
self.setLineMode()
|
self.setLineMode()
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
self.swapPanes(f_dst, f_src)
|
self.swapPanes(f_dst, f_src)
|
||||||
|
@ -3293,7 +3295,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# 'convert_to_upper_case' action
|
# 'convert_to_upper_case' action
|
||||||
def _convert_case(self, to_upper: bool) -> None:
|
def _convert_case(self, to_upper: bool) -> None:
|
||||||
# find range of characters to operate upon
|
# find range of characters to operate upon
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
start, end = self.current_line, self.selection_line
|
start, end = self.current_line, self.selection_line
|
||||||
j0, j1 = self.current_char, self.selection_char
|
j0, j1 = self.current_char, self.selection_char
|
||||||
if end < start or (start == end and j1 < j0):
|
if end < start or (start == end and j1 < j0):
|
||||||
|
@ -3341,7 +3343,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# sort lines
|
# sort lines
|
||||||
def _sort_lines(self, descending: bool) -> None:
|
def _sort_lines(self, descending: bool) -> None:
|
||||||
if self.mode != CHAR_MODE:
|
if self.mode != EditMode.CHAR:
|
||||||
self.setLineMode()
|
self.setLineMode()
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
f = self.current_pane
|
f = self.current_pane
|
||||||
|
@ -3362,7 +3364,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# update line if it changed
|
# update line if it changed
|
||||||
if ss[i] != s:
|
if ss[i] != s:
|
||||||
self.updateText(f, start + i, s)
|
self.updateText(f, start + i, s)
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# ensure the cursor position is valid
|
# ensure the cursor position is valid
|
||||||
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
|
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
|
@ -3377,7 +3379,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
|
|
||||||
# 'remove_trailing_white_space' action
|
# 'remove_trailing_white_space' action
|
||||||
def remove_trailing_white_space(self) -> None:
|
def remove_trailing_white_space(self) -> None:
|
||||||
if self.mode != CHAR_MODE:
|
if self.mode != EditMode.CHAR:
|
||||||
self.setLineMode()
|
self.setLineMode()
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
f = self.current_pane
|
f = self.current_pane
|
||||||
|
@ -3396,7 +3398,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# update line if it changed
|
# update line if it changed
|
||||||
if n < old_n:
|
if n < old_n:
|
||||||
self.updateText(f, i, text[:n] + text[old_n:])
|
self.updateText(f, i, text[:n] + text[old_n:])
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# ensure the cursor position is valid
|
# ensure the cursor position is valid
|
||||||
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
|
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
|
@ -3404,7 +3406,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# 'convert_tabs_to_spaces' action
|
# 'convert_tabs_to_spaces' action
|
||||||
def convert_tabs_to_spaces(self) -> None:
|
def convert_tabs_to_spaces(self) -> None:
|
||||||
# find range of characters to operate upon
|
# find range of characters to operate upon
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
start, end = self.current_line, self.selection_line
|
start, end = self.current_line, self.selection_line
|
||||||
j0, j1 = self.current_char, self.selection_char
|
j0, j1 = self.current_char, self.selection_char
|
||||||
if end < start or (start == end and j1 < j0):
|
if end < start or (start == end and j1 < j0):
|
||||||
|
@ -3449,14 +3451,14 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# 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)
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# ensure the cursor position is valid
|
# ensure the cursor position is valid
|
||||||
self.setCurrentChar(end, j1, start, j0)
|
self.setCurrentChar(end, j1, start, j0)
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
|
|
||||||
# 'convert_leading_spaces_to_tabs' action
|
# 'convert_leading_spaces_to_tabs' action
|
||||||
def convert_leading_spaces_to_tabs(self) -> None:
|
def convert_leading_spaces_to_tabs(self) -> None:
|
||||||
if self.mode != CHAR_MODE:
|
if self.mode != EditMode.CHAR:
|
||||||
self.setLineMode()
|
self.setLineMode()
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
f = self.current_pane
|
f = self.current_pane
|
||||||
|
@ -3479,14 +3481,14 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
# 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)
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# ensure the cursor position is valid
|
# ensure the cursor position is valid
|
||||||
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
|
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
|
|
||||||
# adjust indenting of the selected lines by 'offset' soft tabs
|
# adjust indenting of the selected lines by 'offset' soft tabs
|
||||||
def _adjust_indenting(self, offset: int) -> None:
|
def _adjust_indenting(self, offset: int) -> None:
|
||||||
if self.mode != CHAR_MODE:
|
if self.mode != EditMode.CHAR:
|
||||||
self.setLineMode()
|
self.setLineMode()
|
||||||
# find range of lines to operate upon
|
# find range of lines to operate upon
|
||||||
f = self.current_pane
|
f = self.current_pane
|
||||||
|
@ -3512,7 +3514,7 @@ class FileDiffViewerBase(Gtk.Grid):
|
||||||
tab_width = self.prefs.getInt('display_tab_width')
|
tab_width = self.prefs.getInt('display_tab_width')
|
||||||
s = '\t' * (ws // tab_width) + ' ' * (ws % tab_width)
|
s = '\t' * (ws // tab_width) + ' ' * (ws % tab_width)
|
||||||
self.updateText(f, i, s + text[j:])
|
self.updateText(f, i, s + text[j:])
|
||||||
if self.mode == CHAR_MODE:
|
if self.mode == EditMode.CHAR:
|
||||||
# ensure the cursor position is valid
|
# ensure the cursor position is valid
|
||||||
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
|
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
|
||||||
self.recordEditMode()
|
self.recordEditMode()
|
||||||
|
|
Loading…
Reference in New Issue