Skip to content
Snippets Groups Projects
Commit 1a01e5df authored by Allen, Bruce (CIV)'s avatar Allen, Bruce (CIV)
Browse files

support auto-indent

parent 68ceaf73
No related branches found
No related tags found
No related merge requests found
......@@ -83,8 +83,8 @@ class GUIManager(QObject):
# main window decoration
self.w.setGeometry(200, 100, # used to be 850, 800
self.preferences_manager.preferences["main_window_w"],
self.preferences_manager.preferences["main_window_h"])
self.preferences_manager.initial_preferences["main_window_w"],
self.preferences_manager.initial_preferences["main_window_h"])
self.w.setWindowTitle("Monterey Phoenix v4 - Gryphon GUI %s"%VERSION)
self.w.setWindowIcon(QIcon(":/icons/mp_logo"))
......@@ -152,14 +152,14 @@ class GUIManager(QObject):
# the central widget containing the main split pane
self.mp_code_column = MPCodeColumn(self)
self.mp_code_column.splitter.setSizes(
self.preferences_manager.preferences[
self.preferences_manager.initial_preferences[
"code_column_splitter_sizes"]) # used to be [550, 50, 200]
self.navigation_column = NavigationColumn(self)
self.main_splitter.addWidget(self.mp_code_column)
self.main_splitter.addWidget(self.graph_main_widget.view)
self.main_splitter.addWidget(self.navigation_column)
self.main_splitter.setSizes(
self.preferences_manager.preferences[
self.preferences_manager.initial_preferences[
"main_splitter_sizes"]) # used to be [250, 500, 100]
self.w.setCentralWidget(self.main_splitter)
......@@ -423,6 +423,9 @@ class GUIManager(QObject):
preferences_menu.addAction(self.preferences_manager.action_no_wrap)
preferences_menu.addAction(self.preferences_manager.action_wrap_at_edge)
preferences_menu.addAction(self.preferences_manager.action_wrap_at_word)
preferences_menu.addSeparator()
preferences_menu.addAction(
self.preferences_manager.action_use_auto_indent)
# menu | settings | trace generator path
settings_menu.addAction(self.action_trace_generator_path)
......
......@@ -49,3 +49,6 @@ BRACKET_EXPRESSION = QRegularExpression("[\[\]]") # "[" or "]"
IF_EXPRESSION = QRegularExpression("\\b(IF|FI)\\b") # IF or FI
DO_EXPRESSION = QRegularExpression("\\b(DO|OD)\\b") # DO or OD
# leading whitespace used for auto-indent
LEADING_WHITESPACE_EXPRESSION = QRegularExpression("^\s*")
......@@ -19,7 +19,8 @@ from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import QStringListModel
from mp_code_cursor_highlighter import MPCodeCursorHighlighter
from os_compatibility import control_modifier
from mp_code_expressions import KEYWORD_SET, WORD_EXPRESSION
from mp_code_expressions import KEYWORD_SET, WORD_EXPRESSION, \
LEADING_WHITESPACE_EXPRESSION
# the set of words and the number of words
def words(text):
......@@ -53,6 +54,8 @@ class MPCodeView(QPlainTextEdit):
# connect
preferences_manager.signal_wrap_mode_changed.connect(self.set_wrap_mode)
preferences_manager.signal_use_auto_indent_changed.connect(
self.set_use_auto_indent)
# the cursor highlighter manages cursor highlighting on mouse click
self.mp_code_cursor_highlighter = MPCodeCursorHighlighter(self)
......@@ -66,6 +69,7 @@ class MPCodeView(QPlainTextEdit):
self.line_number_area = LineNumberArea(self)
self.updateLineNumberAreaWidth(0)
self.set_wrap_mode(preferences_manager.wrap_mode())
self.set_use_auto_indent(preferences_manager.use_auto_indent())
# monospace
# https://stackoverflow.com/questions/13027091/how-to-override-tab-width-in-qt
......@@ -104,6 +108,10 @@ class MPCodeView(QPlainTextEdit):
else:
raise RuntimeError("bad")
@pyqtSlot(bool)
def set_use_auto_indent(self, use_auto_indent):
self.use_auto_indent = use_auto_indent
# insert the right portion of the completion text at the end of the cursor
@pyqtSlot(str)
def insert_completion_text(self, completion_text):
......@@ -137,6 +145,14 @@ class MPCodeView(QPlainTextEdit):
suggested_word_list.sort(key=str.lower)
return suggested_word_list
def _add_auto_indent(self):
previous_block_text = self.textCursor().block().previous().text()
if previous_block_text:
previous_whitespace = LEADING_WHITESPACE_EXPRESSION.match(
previous_block_text).captured()
if previous_whitespace:
self.insertPlainText(previous_whitespace)
# intercept keyPress to work with completer
@pyqtSlot(QKeyEvent)
def keyPressEvent(self, e):
......@@ -156,6 +172,10 @@ class MPCodeView(QPlainTextEdit):
if not is_shortcut:
super(MPCodeView, self).keyPressEvent(e)
# auto-indent if auto-indent is enabled and key is enter
if self.use_auto_indent and e.key() in (Qt.Key_Enter, Qt.Key_Return):
self._add_auto_indent()
# recognize CTRL or SHIFT
ctrl_or_shift = e.modifiers() & (control_modifier() | Qt.ShiftModifier)
......
"""Access persistent user settings using this manager.
Interfaces:
* wrap_mode
* use_auto_indent
Signals:
* signal_wrap_mode_changed
* signal_use_auto_indent_changed
Provides preferences and actions.
Change preferences using interfaces. Do not change preferences directly.
"""
......@@ -22,6 +30,9 @@ _WRAP_AT_WORD = ["wrap_at_word", "Wrap at word boundary",
_WRAP_MODES = {_NO_WRAP[0], _WRAP_AT_EDGE[0], _WRAP_AT_WORD[0]}
_DEFAULT_WRAP_MODE = _WRAP_AT_EDGE[0]
# code editor: apply auto-indent on CR
_DEFAULT_AUTO_INDENT = True
def _wrap_mode(label):
if label == _NO_WRAP[1]:
mode = _NO_WRAP[0]
......@@ -36,6 +47,60 @@ def _wrap_mode(label):
def _in_range(value, min_value, max_value):
return value >= min_value and value <= max_value
def _load():
# get user preferences
p_user = dict()
if os.path.exists(USER_PREFERENCES_FILENAME):
try:
with open(USER_PREFERENCES_FILENAME) as f:
p_user = json.load(f)
except Exception as e:
print("Invalid preferences file %s: %s"
%(USER_PREFERENCES_FILENAME, str(e)))
# try to accept values but never fail on invalid values
# start out with defaults
preferences = {
"main_window_w": 850,
"main_window_h": 800,
"main_splitter_sizes": [250, 500, 100],
"code_column_splitter_sizes": [550, 50, 200],
"wrap_mode": "%s"%_DEFAULT_WRAP_MODE,
"use_auto_indent": True
}
try:
if _in_range(p_user["main_window_h"], 200, 2000):
preferences["main_window_h"] = p_user["main_window_h"]
if _in_range(p_user["main_window_w"], 200, 2000):
preferences["main_window_w"] = p_user["main_window_w"]
if _in_range(p_user["main_splitter_sizes"][0], 0, 2000):
preferences["main_splitter_sizes"][0] \
= p_user["main_splitter_sizes"][0]
if _in_range(p_user["main_splitter_sizes"][1], 0, 2000):
preferences["main_splitter_sizes"][1] \
= p_user["main_splitter_sizes"][1]
if _in_range(p_user["main_splitter_sizes"][2], 0, 2000):
preferences["main_splitter_sizes"][2] \
= p_user["main_splitter_sizes"][2]
if _in_range(p_user["code_column_splitter_sizes"][0], 0, 2000):
preferences["code_column_splitter_sizes"][0] \
= p_user["code_column_splitter_sizes"][0]
if _in_range(p_user["code_column_splitter_sizes"][1], 0, 2000):
preferences["code_column_splitter_sizes"][1] \
= p_user["code_column_splitter_sizes"][1]
if _in_range(p_user["code_column_splitter_sizes"][2], 0, 2000):
preferences["code_column_splitter_sizes"][2] \
= p_user["code_column_splitter_sizes"][2]
if p_user["wrap_mode"] in _WRAP_MODES:
preferences["wrap_mode"] = p_user["wrap_mode"]
if type(p_user["use_auto_indent"]) == bool:
preferences["use_auto_indent"] = p_user["use_auto_indent"]
except Exception as e:
print("Invalid preference value in file %s: %s"
%(USER_PREFERENCES_FILENAME, str(e)))
return preferences
class PreferencesManager(QObject):
"""
Supports user preferences.
......@@ -43,58 +108,11 @@ class PreferencesManager(QObject):
# signal
signal_wrap_mode_changed = pyqtSignal(str, name='wrapModeChanged')
# try to accept values but never fail on invalid values
def _accept_values(self, p_new):
if _in_range(p_new["main_window_h"], 200, 2000):
self.preferences["main_window_h"] = p_new["main_window_h"]
if _in_range(p_new["main_window_w"], 200, 2000):
self.preferences["main_window_w"] = p_new["main_window_w"]
if _in_range(p_new["main_splitter_sizes"][0], 0, 2000):
self.preferences["main_splitter_sizes"][0] \
= p_new["main_splitter_sizes"][0]
if _in_range(p_new["main_splitter_sizes"][1], 0, 2000):
self.preferences["main_splitter_sizes"][1] \
= p_new["main_splitter_sizes"][1]
if _in_range(p_new["main_splitter_sizes"][2], 0, 2000):
self.preferences["main_splitter_sizes"][2] \
= p_new["main_splitter_sizes"][2]
if _in_range(p_new["code_column_splitter_sizes"][0], 0, 2000):
self.preferences["code_column_splitter_sizes"][0] \
= p_new["code_column_splitter_sizes"][0]
if _in_range(p_new["code_column_splitter_sizes"][1], 0, 2000):
self.preferences["code_column_splitter_sizes"][1] \
= p_new["code_column_splitter_sizes"][1]
if _in_range(p_new["code_column_splitter_sizes"][2], 0, 2000):
self.preferences["code_column_splitter_sizes"][2] \
= p_new["code_column_splitter_sizes"][2]
if p_new["wrap_mode"] in _WRAP_MODES:
self.preferences["wrap_mode"] = p_new["wrap_mode"]
def _load(self):
# start with defaults
self.preferences = {
"main_window_w": 850,
"main_window_h": 800,
"main_splitter_sizes": [250, 500, 100],
"code_column_splitter_sizes": [550, 50, 200],
"wrap_mode": "%s"%_DEFAULT_WRAP_MODE
}
# take user preferences but don't keep obsolete keys
if os.path.exists(USER_PREFERENCES_FILENAME):
try:
with open(USER_PREFERENCES_FILENAME) as f:
new_preferences = json.load(f)
self._accept_values(new_preferences)
except Exception as e:
print("Invalid preferences file %s: %s"
%(USER_PREFERENCES_FILENAME, str(e)))
signal_use_auto_indent_changed = pyqtSignal(bool, name='autoIndentChanged')
def save(self):
# collect preferences
preferences = dict()
preferences["wrap_mode"] = self.wrap_mode()
geometry = self.gui_manager.w.geometry()
preferences["main_window_w"] = geometry.width()
preferences["main_window_h"] = geometry.height()
......@@ -102,9 +120,11 @@ class PreferencesManager(QObject):
self.gui_manager.main_splitter.sizes()
preferences["code_column_splitter_sizes"] = \
self.gui_manager.mp_code_column.splitter.sizes()
preferences["wrap_mode"] = self.wrap_mode()
preferences["use_auto_indent"] = self.use_auto_indent()
# export preferences in JSON
if preferences != self.preferences:
if preferences != self.initial_preferences:
try:
with open(USER_PREFERENCES_FILENAME, "w") as f:
json.dump(preferences, f)
......@@ -137,13 +157,24 @@ class PreferencesManager(QObject):
self.wrap_group.addAction(self.action_wrap_at_word)
self.wrap_group.triggered.connect(self._set_wrap_mode)
# action settings preferences code editor text wrap at word boundary
self.action_use_auto_indent = QAction("Auto-indent")
self.action_use_auto_indent.setStatusTip("Auto-indent code editor text")
self.action_use_auto_indent.setCheckable(True)
self.action_use_auto_indent.triggered.connect(self._set_use_auto_indent)
# initial value
self._load()
self._set_wrap_button(self.preferences["wrap_mode"])
preferences = _load()
self._set_wrap_button(preferences["wrap_mode"])
self.action_use_auto_indent.setChecked(preferences["use_auto_indent"])
self.initial_preferences = preferences
def wrap_mode(self):
return _wrap_mode(self.wrap_group.checkedAction().text())
def use_auto_indent(self):
return self.action_use_auto_indent.isChecked()
# set the active wrap action button
def _set_wrap_button(self, wrap_mode):
if wrap_mode == _NO_WRAP[0]:
......@@ -155,7 +186,6 @@ class PreferencesManager(QObject):
else:
print("mode %s not supported. Using %s."%(wrap_mode,
_DEFAULT_WRAP_MODE))
preferences["wrap_mode"] = _DEFAULT_WRAP_MODE
if _DEFAULT_WRAP_MODE == _NO_WRAP[0]:
self.action_no_wrap.setChecked(True)
elif _DEFAULT_WRAP_MODE == _WRAP_AT_EDGE[0]:
......@@ -170,3 +200,8 @@ class PreferencesManager(QObject):
wrap_mode = _wrap_mode(action.text())
self.signal_wrap_mode_changed.emit(_wrap_mode(action.text()))
@pyqtSlot(bool)
def _set_use_auto_indent(self, is_auto_indent):
self.signal_use_auto_indent_changed.emit(
self.action_use_auto_indent.isChecked())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment