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 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

View File

@ -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()