Add static typing for main

This commit is contained in:
Romain Failliot 2022-01-09 18:27:15 -05:00
parent 0a2d3cc3e0
commit 86137e90c5
2 changed files with 145 additions and 137 deletions

View File

@ -26,7 +26,7 @@ import stat
import webbrowser
from gettext import gettext as _
from typing import Optional
from typing import List, Optional
from urllib.parse import urlparse
from diffuse import constants
@ -35,9 +35,10 @@ from diffuse.dialogs import AboutDialog, FileChooserDialog, NumericDialog, Searc
from diffuse.preferences import Preferences
from diffuse.resources import theResources
from diffuse.utils import LineEnding
from diffuse.vcs.vcs_interface import VcsInterface
from diffuse.vcs.vcs_registry import VcsRegistry
from diffuse.widgets import FileDiffViewerBase
from diffuse.widgets import createMenu, LINE_MODE, CHAR_MODE, ALIGN_MODE
from diffuse.widgets import FileDiffViewerBase, EditMode
from diffuse.widgets import createMenu
import gi # type: ignore
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
# presses.
class NotebookTab(Gtk.EventBox):
def __init__(self, name, stock):
def __init__(self, name: str, stock: str) -> None:
Gtk.EventBox.__init__(self)
self.set_visible_window(False)
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
@ -66,13 +67,16 @@ class NotebookTab(Gtk.EventBox):
image.set_from_stock(stock, Gtk.IconSize.MENU)
hbox.pack_start(image, False, False, 5)
image.show()
self.label = label = Gtk.Label.new(name)
label = Gtk.Label.new(name)
# left justify the widget
label.set_xalign(0.0)
label.set_yalign(0.5)
hbox.pack_start(label, True, True, 0)
label.show()
self.button = button = Gtk.Button.new()
self.label = label
button = Gtk.Button.new()
button.set_relief(Gtk.ReliefStyle.NONE)
image = Gtk.Image.new()
image.set_from_stock(Gtk.STOCK_CLOSE, Gtk.IconSize.MENU)
@ -81,13 +85,15 @@ class NotebookTab(Gtk.EventBox):
button.set_tooltip_text(_('Close Tab'))
hbox.pack_start(button, False, False, 0)
button.show()
self.button = button
self.add(hbox)
hbox.show()
def get_text(self):
def get_text(self) -> str:
return self.label.get_text()
def set_text(self, s):
def set_text(self, s: str) -> None:
self.label.set_text(s)
@ -99,7 +105,7 @@ class FileInfo:
# name of codec used to translate the file contents to unicode text
self.encoding = encoding
# the VCS object
self.vcs = vcs
self.vcs: VcsInterface = vcs
# revision used to retrieve file from the VCS
self.revision = revision
# alternate text to display instead of the actual file name
@ -147,7 +153,7 @@ class Diffuse(Gtk.Window):
self.emit(s)
# creates an appropriate title for the pane header
def updateTitle(self):
def updateTitle(self) -> None:
ss = []
info = self.info
if info.label is not None:
@ -166,7 +172,7 @@ class Diffuse(Gtk.Window):
self.emit('title_changed')
# set num edits
def setEdits(self, has_edits):
def setEdits(self, has_edits: bool) -> None:
if self.has_edits != has_edits:
self.has_edits = has_edits
self.updateTitle()
@ -198,8 +204,8 @@ class Diffuse(Gtk.Window):
self.show_all()
# set the cursor label
def updateCursor(self, viewer, f):
if viewer.mode == CHAR_MODE and viewer.current_pane == f:
def updateCursor(self, viewer: FileDiffViewerBase, f: int) -> None:
if viewer.mode == EditMode.CHAR and viewer.current_pane == f:
# # TODO: Find a fix for the column bug (resizing issue when editing a line)
# j = viewer.current_char
# if j > 0:
@ -212,7 +218,7 @@ class Diffuse(Gtk.Window):
self.cursor.set_text(s)
# set the format label
def setFormat(self, s):
def setFormat(self, s: LineEnding) -> None:
v = []
if s & LineEnding.DOS_FORMAT:
v.append('DOS')
@ -223,19 +229,19 @@ class Diffuse(Gtk.Window):
self.format.set_text('/'.join(v))
# set the format label
def setEncoding(self, s):
def setEncoding(self, s: str) -> None:
if s is None:
s = ''
self.encoding.set_text(s)
def __init__(self, n, prefs, title):
FileDiffViewerBase.__init__(self, n, prefs)
def __init__(self, n: int, prefs: Preferences, title: str) -> None:
super().__init__(n, prefs)
self.title = title
self.status = ''
self.status: Optional[str] = ''
self.headers = []
self.footers = []
self.headers: List[Diffuse.FileDiffViewer.PaneHeader] = []
self.footers: List[Diffuse.FileDiffViewer.PaneFooter] = []
for i in range(n):
# pane header
w = Diffuse.FileDiffViewer.PaneHeader()
@ -272,7 +278,7 @@ class Diffuse(Gtk.Window):
# convenience method to request confirmation before loading a file if
# 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:
# warn users of any unsaved changes they might lose
dialog = Gtk.MessageDialog(
@ -358,7 +364,7 @@ class Diffuse(Gtk.Window):
# load a new file into pane 'f'
# 'info' indicates the name of the file and how to retrieve it from the
# version control system if applicable
def load(self, f, info):
def load(self, f: int, info: FileInfo) -> None:
name = info.name
encoding = info.encoding
stat = None
@ -371,7 +377,7 @@ class Diffuse(Gtk.Window):
if rev is None:
# load the contents of a plain file
with open(name, 'rb') as fd:
s = fd.read()
contents = fd.read()
# get the file's modification times so we can detect changes
stat = os.stat(name)
else:
@ -379,12 +385,12 @@ class Diffuse(Gtk.Window):
raise IOError('Not under version control.')
fullname = os.path.abspath(name)
# 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
if encoding is None:
s, encoding = self.prefs.convertToUnicode(s)
s, encoding = self.prefs.convertToUnicode(contents)
else:
s = str(s, encoding=encoding)
s = str(contents, encoding=encoding)
ss = utils.splitlines(s)
except (IOError, OSError, UnicodeDecodeError, LookupError):
# FIXME: this can occur before the toplevel window is drawn
@ -408,7 +414,7 @@ class Diffuse(Gtk.Window):
self.setSyntax(syntax)
# 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]
info = h.info
if not reload:
@ -487,7 +493,7 @@ class Diffuse(Gtk.Window):
pass
# 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]
info = h.info
name, encoding, rev, label = info.name, info.encoding, info.revision, info.label
@ -642,15 +648,15 @@ class Diffuse(Gtk.Window):
self.updateStatus()
# update the viewer's current status message
def updateStatus(self):
if self.mode == LINE_MODE:
def updateStatus(self) -> None:
if self.mode == EditMode.LINE:
s = _(
'Press the enter key or double click to edit. Press the space bar or use the '
'RMB menu to manually align.'
)
elif self.mode == CHAR_MODE:
elif self.mode == EditMode.CHAR:
s = _('Press the escape key to finish editing.')
elif self.mode == ALIGN_MODE:
elif self.mode == EditMode.ALIGN:
s = _(
'Select target line and press the space bar to align. Press the escape key to '
'cancel.'
@ -661,7 +667,7 @@ class Diffuse(Gtk.Window):
self.emit('status_changed', s)
# gets the status bar text
def getStatus(self):
def getStatus(self) -> Optional[str]:
return self.status
# callback to display the cursor in a pane
@ -674,7 +680,7 @@ class Diffuse(Gtk.Window):
self.footers[f].setFormat(fmt)
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'))
# 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)
# search history is application wide
self.search_pattern = None
self.search_history = []
self.search_pattern: Optional[str] = None
self.search_history: List[str] = []
self.connect('delete-event', self.delete_cb)
accel_group = Gtk.AccelGroup()
@ -968,7 +974,7 @@ class Diffuse(Gtk.Window):
)
# load state information that should persist across sessions
def loadState(self, statepath):
def loadState(self, statepath: str) -> None:
if os.path.isfile(statepath):
try:
f = open(statepath, 'r')
@ -998,7 +1004,7 @@ class Diffuse(Gtk.Window):
self.maximize()
# save state information that should persist across sessions
def saveState(self, statepath):
def saveState(self, statepath: str) -> None:
try:
ss = []
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
# 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
model = Gtk.ListStore.new([
GObject.TYPE_BOOLEAN,
@ -1144,12 +1150,12 @@ class Diffuse(Gtk.Window):
menu.popup(None, None, None, event.button, event.time)
# update window's title
def updateTitle(self, viewer):
def updateTitle(self, viewer: FileDiffViewer) -> None:
title = self.notebook.get_tab_label(viewer).get_text()
self.set_title(f'{title} - {constants.APP_NAME}')
# update the message in the status bar
def setStatus(self, s):
def setStatus(self, s: Optional[str]) -> None:
sb = self.statusbar
context = sb.get_context_id('Message')
sb.pop(context)
@ -1358,7 +1364,7 @@ class Diffuse(Gtk.Window):
return True
# 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())
# 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
# current viewer pane
def find(self, force, reverse):
def find(self, force: bool, reverse: bool) -> None:
viewer = self.getCurrentViewer()
if force or self.search_pattern is None:
# construct search dialog

View File

@ -21,9 +21,9 @@ import difflib
import os
import unicodedata
from enum import IntFlag
from enum import Flag, IntFlag, auto
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.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
# 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,
# and hotkey behavior
LINE_MODE = 0
CHAR_MODE = 1
ALIGN_MODE = 2
class EditMode(Flag):
LINE = auto()
CHAR = auto()
ALIGN = auto()
# 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:
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.prefs = prefs
self.string_width_cache = {}
self.string_width_cache: Dict[str, Optional[int]] = {}
self.options = {}
# diff blocks
@ -217,7 +219,7 @@ class FileDiffViewerBase(Gtk.Grid):
self.diffmap_cache = None
# editing mode
self.mode = LINE_MODE
self.mode = EditMode.LINE
self.current_pane = 1
self.current_line = 0
self.current_char = 0
@ -228,7 +230,7 @@ class FileDiffViewerBase(Gtk.Grid):
self.cursor_column = -1
# keybindings
self._line_mode_actions = {
self._line_mode_actions: Dict[str, Callable] = {
'enter_align_mode': self._line_mode_enter_align_mode,
'enter_character_mode': self.setCharMode,
'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_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_character_mode': self.setCharMode,
'first_line': self._first_line,
@ -274,10 +276,10 @@ class FileDiffViewerBase(Gtk.Grid):
'page_down': self._line_mode_page_down,
'align': self._align_text
}
self._character_mode_actions = {
self._character_mode_actions: Dict[str, Callable] = {
'enter_line_mode': self.setLineMode
}
self._button_actions = {
self._button_actions: Dict[str, Callable] = {
'undo': self.undo,
'redo': self.redo,
'cut': self.cut,
@ -315,7 +317,7 @@ class FileDiffViewerBase(Gtk.Grid):
}
# create panes
self.dareas = []
self.dareas: List[Gtk.DrawingArea] = []
self.panes: List[FileDiffViewerBase.Pane] = []
self.hadj = 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
for c in s:
try:
w = _char_width_cache[c]
w = self._char_width_cache[c]
except KeyError:
v = ord(c)
if v < 32:
@ -423,23 +425,23 @@ class FileDiffViewerBase(Gtk.Grid):
w = tab_width - col % tab_width
elif c == '\n':
w = 1
_char_width_cache[c] = w
self._char_width_cache[c] = w
else:
w = 2
_char_width_cache[c] = w
self._char_width_cache[c] = w
else:
if unicodedata.east_asian_width(c) in 'WF':
w = 2
else:
w = 1
_char_width_cache[c] = w
self._char_width_cache[c] = w
col += w
return col
# returns the 'column width' for a single character created at column 'i'
def characterWidth(self, i: int, c: str) -> int:
try:
return _char_width_cache[c]
return self._char_width_cache[c]
except KeyError:
v = ord(c)
if v < 32:
@ -454,7 +456,7 @@ class FileDiffViewerBase(Gtk.Grid):
w = 2
else:
w = 1
_char_width_cache[c] = w
self._char_width_cache[c] = w
return w
# translates a string into an array of the printable representation for
@ -493,32 +495,32 @@ class FileDiffViewerBase(Gtk.Grid):
col += self.characterWidth(col, c)
return result
# changes the viewer's mode to LINE_MODE
# changes the viewer's mode to EditMode.LINE
def setLineMode(self) -> None:
if self.mode != LINE_MODE:
if self.mode == CHAR_MODE:
if self.mode != EditMode.LINE:
if self.mode == EditMode.CHAR:
self._im_focus_out()
self.im_context.reset()
self._im_set_preedit(None)
self.current_char = 0
self.selection_char = 0
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.current_pane].queue_draw()
self.align_pane = 0
self.align_line = 0
self.mode = LINE_MODE
self.mode = EditMode.LINE
self.emit('cursor_changed')
self.emit('mode_changed')
# changes the viewer's mode to CHAR_MODE
def setCharMode(self) -> None:
if self.mode != CHAR_MODE:
if self.mode == LINE_MODE:
if self.mode != EditMode.CHAR:
if self.mode == EditMode.LINE:
self.cursor_column = -1
self.setCurrentChar(self.current_line, 0)
elif self.mode == ALIGN_MODE:
elif self.mode == EditMode.ALIGN:
self.dareas[self.align_pane].queue_draw()
self.cursor_column = -1
self.align_pane = 0
@ -526,7 +528,7 @@ class FileDiffViewerBase(Gtk.Grid):
self.setCurrentChar(self.current_line, 0)
self._im_focus_in()
self.im_context.reset()
self.mode = CHAR_MODE
self.mode = EditMode.CHAR
self.emit('cursor_changed')
self.emit('mode_changed')
@ -584,10 +586,10 @@ class FileDiffViewerBase(Gtk.Grid):
# 'undo' action
def undo(self) -> None:
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
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:
# move the block to the redo stack
block = self.undos.pop()
@ -600,8 +602,8 @@ class FileDiffViewerBase(Gtk.Grid):
# 'redo' action
def redo(self) -> None:
self.undoblock, old_block = None, self.undoblock
if self.mode in (LINE_MODE, CHAR_MODE):
if self.mode == CHAR_MODE:
if self.mode in (EditMode.LINE, EditMode.CHAR):
if self.mode == EditMode.CHAR:
# avoid implicit preedit commit when an redo changes the mode
self.im_context.reset()
if len(self.redos) > 0:
@ -657,10 +659,10 @@ class FileDiffViewerBase(Gtk.Grid):
text.append(line.modified_text)
for s in text:
if s is not None:
w = string_width_cache.get(s, None)
if w is None:
string_width_cache[s] = w = stringWidth(s)
pane.line_lengths = max(pane.line_lengths, digit_width * w)
swc = string_width_cache.get(s, None)
if swc is None:
string_width_cache[s] = swc = stringWidth(s)
pane.line_lengths = max(pane.line_lengths, digit_width * swc)
# compute the maximum extents
num_lines, line_lengths = 0, 0
for pane in self.panes:
@ -1282,7 +1284,7 @@ class FileDiffViewerBase(Gtk.Grid):
pane = self.panes[f]
nlines = len(pane.lines)
line0, line1 = self.selection_line, self.current_line
if self.mode == LINE_MODE:
if self.mode == EditMode.LINE:
col0, col1 = 0, 0
if line1 < line0:
line0, line1 = line1, line0
@ -1349,7 +1351,7 @@ class FileDiffViewerBase(Gtk.Grid):
for i in range(delta):
self.updateText(f, line0 + n_need + i, None)
# update selection
if self.mode == LINE_MODE:
if self.mode == EditMode.LINE:
self.setCurrentLine(f, line0 + max(n_need, 1) - 1, line0)
else:
self.setCurrentChar(cur_line, lastcol)
@ -1523,7 +1525,7 @@ class FileDiffViewerBase(Gtk.Grid):
self.selection_line = selection_line
self.selection_char = selection_char
self.cursor_column = cursor_column
if mode == CHAR_MODE:
if mode == EditMode.CHAR:
self.setCurrentChar(self.current_line, self.current_char, True)
else:
self.setCurrentLine(self.current_pane, self.current_line, self.selection_line)
@ -1555,7 +1557,7 @@ class FileDiffViewerBase(Gtk.Grid):
elif upper > v + 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
def setCurrentLine(self, f: int, i: int, selection: Optional[int] = None) -> None:
# 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
def hasPreedit(self, f: int, i: int) -> bool:
return (
self.mode == CHAR_MODE and
self.mode == EditMode.CHAR and
self.current_pane == f and
self.current_line == i and
self.im_preedit is not None
@ -1602,7 +1604,7 @@ class FileDiffViewerBase(Gtk.Grid):
# inform input method about cursor motion
def _cursor_position_changed(self, recompute):
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
# update input method
h = self.font_height
if recompute:
@ -1698,7 +1700,7 @@ class FileDiffViewerBase(Gtk.Grid):
f = self.current_pane
start, end = self.selection_line, self.current_line
# find extents of selection
if self.mode == LINE_MODE:
if self.mode == EditMode.LINE:
if end < start:
start, end = end, start
end += 1
@ -1722,11 +1724,11 @@ class FileDiffViewerBase(Gtk.Grid):
# expands the selection to include everything
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
self.selection_line = 0
self.current_line = len(self.panes[f].lines)
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
self.selection_char = 0
self.current_char = 0
self.dareas[f].queue_draw()
@ -1756,7 +1758,7 @@ class FileDiffViewerBase(Gtk.Grid):
if y < 0:
x, y = -1, 0
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))
j = self._getPickedCharacter(text, x, True)
if extend:
@ -1765,9 +1767,9 @@ class FileDiffViewerBase(Gtk.Grid):
si, sj = None, None
self.setCurrentChar(i, j, si, sj)
else:
if self.mode == ALIGN_MODE:
if self.mode == EditMode.ALIGN:
extend = False
elif self.mode == CHAR_MODE:
elif self.mode == EditMode.CHAR:
self.setLineMode()
if extend and f == self.current_pane:
selection = self.selection_line
@ -1786,17 +1788,17 @@ class FileDiffViewerBase(Gtk.Grid):
# left mouse button
if event.type == Gdk.EventType._2BUTTON_PRESS:
# double click
if self.mode == ALIGN_MODE:
if self.mode == EditMode.ALIGN:
self.setLineMode()
if self.mode == LINE_MODE:
if self.mode == EditMode.LINE:
# change to CHAR_MODE
self.setCurrentLine(f, i)
# silently switch mode so the viewer does not scroll yet.
self.mode = CHAR_MODE
self.mode = EditMode.CHAR
self._im_focus_in()
self.button_press(f, x, y, False)
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
text = utils.strip_eol(self.getLineText(f, i))
if text is not None:
@ -1812,7 +1814,7 @@ class FileDiffViewerBase(Gtk.Grid):
self.setCurrentChar(i, j, i, k)
elif event.type == Gdk.EventType._3BUTTON_PRESS:
# 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)
self.setCurrentChar(i2, 0, i, 0)
else:
@ -1822,7 +1824,7 @@ class FileDiffViewerBase(Gtk.Grid):
self.button_press(f, x, y, extend)
elif event.button == 2:
# 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.openUndoBlock()
Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY).request_text(
@ -1832,11 +1834,11 @@ class FileDiffViewerBase(Gtk.Grid):
elif event.button == 3:
# right mouse button, raise context sensitive menu
can_align = (
self.mode == LINE_MODE and
self.mode == EditMode.LINE and
(f in (self.current_pane + 1, f == self.current_pane - 1)))
can_isolate = self.mode == LINE_MODE and f == self.current_pane
can_merge = self.mode == LINE_MODE and f != self.current_pane
can_select = self.mode in (LINE_MODE, CHAR_MODE) and f == self.current_pane
can_isolate = self.mode == EditMode.LINE and f == self.current_pane
can_merge = self.mode == EditMode.LINE 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)
menu = createMenu([
@ -2136,14 +2138,14 @@ class FileDiffViewerBase(Gtk.Grid):
preedit_bg_colour = (colour * alpha).over(preedit_bg_colour)
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
cr.paint()
if self.mode == ALIGN_MODE:
if self.mode == EditMode.ALIGN:
# draw align
if self.align_pane == f and self.align_line == i:
colour = theResources.getColour('alignment')
alpha = theResources.getFloat('alignment_opacity')
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
cr.paint()
elif self.mode == LINE_MODE:
elif self.mode == EditMode.LINE:
# draw line selection
if self.current_pane == f:
start, end = self.selection_line, self.current_line
@ -2154,7 +2156,7 @@ class FileDiffViewerBase(Gtk.Grid):
alpha = theResources.getFloat('line_selection_opacity')
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
cr.paint()
elif self.mode == CHAR_MODE:
elif self.mode == EditMode.CHAR:
# draw char selection
if self.current_pane == f and text is not None:
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:
# 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())
if has_preedit:
# we have preedit text
@ -2312,7 +2314,7 @@ class FileDiffViewerBase(Gtk.Grid):
cr.move_to(x_pos + 0.5, y_start)
cr.rel_line_to(0, h)
cr.stroke()
elif self.mode in (LINE_MODE, ALIGN_MODE):
elif self.mode in (EditMode.LINE, EditMode.ALIGN):
# draw the line editing cursor
colour = theResources.getColour('cursor')
cr.set_source_rgb(colour.red, colour.green, colour.blue)
@ -2485,11 +2487,11 @@ class FileDiffViewerBase(Gtk.Grid):
# 'enter_align_mode' keybinding action
def _line_mode_enter_align_mode(self):
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
self._im_focus_out()
self.im_context.reset()
self._im_set_preedit(None)
self.mode = ALIGN_MODE
self.mode = EditMode.ALIGN
self.selection_line = self.current_line
self.align_pane = self.current_pane
self.align_line = self.current_line
@ -2597,7 +2599,7 @@ class FileDiffViewerBase(Gtk.Grid):
# input method callback for committed text
def im_commit_cb(self, im, s):
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
self.openUndoBlock()
self.replaceText(s)
self.closeUndoBlock()
@ -2605,7 +2607,7 @@ class FileDiffViewerBase(Gtk.Grid):
# update the cached preedit text
def _im_set_preedit(self, p):
self.im_preedit = p
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
f, i = self.current_pane, self.current_line
self._queue_draw_lines(f, i)
if f > 0:
@ -2616,7 +2618,7 @@ class FileDiffViewerBase(Gtk.Grid):
# queue a redraw for location of preedit text
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()
if len(s) > 0:
# 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
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
s = utils.null_to_empty(self.getLineText(self.current_pane, self.current_line))
im.set_surrounding(s, len(s), self.current_char)
@ -2636,13 +2638,13 @@ class FileDiffViewerBase(Gtk.Grid):
# callback for 'focus_in_event'
def focus_in_cb(self, widget, event):
self.has_focus = True
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
# notify the input method of the focus change
self._im_focus_in()
# callback for 'focus_out_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
self._im_focus_out()
self.has_focus = False
@ -2650,7 +2652,7 @@ class FileDiffViewerBase(Gtk.Grid):
# callback for keyboard events
# only keypresses that are not handled by menu item accelerators reach here
def key_press_cb(self, widget, event):
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
# update input method
if self.im_context.filter_keypress(event):
return True
@ -2660,13 +2662,13 @@ class FileDiffViewerBase(Gtk.Grid):
if event.state & Gdk.ModifierType.LOCK_MASK:
mask ^= Gdk.ModifierType.SHIFT_MASK
self.openUndoBlock()
if self.mode == LINE_MODE:
if self.mode == EditMode.LINE:
# check if the keyval matches a line mode action
action = theResources.getActionForKey('line_mode', event.keyval, mask)
if action in self._line_mode_actions:
self._line_mode_actions[action]()
retval = True
elif self.mode == CHAR_MODE:
elif self.mode == EditMode.CHAR:
f = self.current_pane
if event.state & Gdk.ModifierType.SHIFT_MASK:
si, sj = self.selection_line, self.selection_char
@ -2918,7 +2920,7 @@ class FileDiffViewerBase(Gtk.Grid):
# handle all other printable characters
elif len(event.string) > 0:
self.replaceText(event.string)
elif self.mode == ALIGN_MODE:
elif self.mode == EditMode.ALIGN:
# check if the keyval matches an align mode action
action = theResources.getActionForKey('align_mode', event.keyval, mask)
if action in self._align_mode_actions:
@ -2929,18 +2931,18 @@ class FileDiffViewerBase(Gtk.Grid):
# 'copy' action
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())
# 'cut' action
def cut(self) -> None:
if self.mode in (LINE_MODE, CHAR_MODE):
if self.mode in (EditMode.LINE, EditMode.CHAR):
self.copy()
self.replaceText('')
# callback used when receiving clipboard text
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
# Gtk.Clipboard.get so we may need to create our own undo block
needs_block = (self.undoblock is None)
@ -2977,7 +2979,7 @@ class FileDiffViewerBase(Gtk.Grid):
# 'dismiss_all_edits' action
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)
# callback for find menu item
@ -3268,7 +3270,7 @@ class FileDiffViewerBase(Gtk.Grid):
# swap the contents of two panes
def swap_panes(self, f_dst: int, f_src: int) -> None:
if 0 <= f_dst < len(self.panes):
if self.mode == ALIGN_MODE:
if self.mode == EditMode.ALIGN:
self.setLineMode()
self.recordEditMode()
self.swapPanes(f_dst, f_src)
@ -3293,7 +3295,7 @@ class FileDiffViewerBase(Gtk.Grid):
# 'convert_to_upper_case' action
def _convert_case(self, to_upper: bool) -> None:
# 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
j0, j1 = self.current_char, self.selection_char
if end < start or (start == end and j1 < j0):
@ -3341,7 +3343,7 @@ class FileDiffViewerBase(Gtk.Grid):
# sort lines
def _sort_lines(self, descending: bool) -> None:
if self.mode != CHAR_MODE:
if self.mode != EditMode.CHAR:
self.setLineMode()
self.recordEditMode()
f = self.current_pane
@ -3362,7 +3364,7 @@ class FileDiffViewerBase(Gtk.Grid):
# update line if it changed
if ss[i] != s:
self.updateText(f, start + i, s)
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
# ensure the cursor position is valid
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
self.recordEditMode()
@ -3377,7 +3379,7 @@ class FileDiffViewerBase(Gtk.Grid):
# 'remove_trailing_white_space' action
def remove_trailing_white_space(self) -> None:
if self.mode != CHAR_MODE:
if self.mode != EditMode.CHAR:
self.setLineMode()
self.recordEditMode()
f = self.current_pane
@ -3396,7 +3398,7 @@ class FileDiffViewerBase(Gtk.Grid):
# update line if it changed
if n < 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
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
self.recordEditMode()
@ -3404,7 +3406,7 @@ class FileDiffViewerBase(Gtk.Grid):
# 'convert_tabs_to_spaces' action
def convert_tabs_to_spaces(self) -> None:
# 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
j0, j1 = self.current_char, self.selection_char
if end < start or (start == end and j1 < j0):
@ -3449,14 +3451,14 @@ class FileDiffViewerBase(Gtk.Grid):
# update line only if it changed
if text != s:
self.updateText(f, i, s)
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
# ensure the cursor position is valid
self.setCurrentChar(end, j1, start, j0)
self.recordEditMode()
# 'convert_leading_spaces_to_tabs' action
def convert_leading_spaces_to_tabs(self) -> None:
if self.mode != CHAR_MODE:
if self.mode != EditMode.CHAR:
self.setLineMode()
self.recordEditMode()
f = self.current_pane
@ -3479,14 +3481,14 @@ class FileDiffViewerBase(Gtk.Grid):
# update line only if it changed
if text != s:
self.updateText(f, i, s)
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
# ensure the cursor position is valid
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
self.recordEditMode()
# adjust indenting of the selected lines by 'offset' soft tabs
def _adjust_indenting(self, offset: int) -> None:
if self.mode != CHAR_MODE:
if self.mode != EditMode.CHAR:
self.setLineMode()
# find range of lines to operate upon
f = self.current_pane
@ -3512,7 +3514,7 @@ class FileDiffViewerBase(Gtk.Grid):
tab_width = self.prefs.getInt('display_tab_width')
s = '\t' * (ws // tab_width) + ' ' * (ws % tab_width)
self.updateText(f, i, s + text[j:])
if self.mode == CHAR_MODE:
if self.mode == EditMode.CHAR:
# ensure the cursor position is valid
self.setCurrentChar(self.current_line, 0, self.selection_line, 0)
self.recordEditMode()