Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

footlinks: Add threshold configuration for footlinks. #841

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,13 @@ theme=default
# Autohide defaults to 'no_autohide', but can be set to 'autohide' to hide the left & right panels except when focused.
autohide=autohide
# Footlinks default to 'enabled', but can be set to 'disabled' to hide footlinks.
# disabled won't show any footlinks.
# enabled would show the first 3.
footlinks=disabled
# If you need more flexibility, use maximum-footlinks.
# Maximum footlinks to be shown, defaults to 3, but can be set to any value>=0.
# Cannot be used along with footlinks, use either of them.
maximum-footlinks=3
# Notify defaults to 'disabled', but can be set to 'enabled' to display notifications (see next section).
notify=enabled
# Color depth defaults to 256, but can be set to 1 (for monochrome) or 16.
Expand Down
104 changes: 99 additions & 5 deletions tests/cli/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def test_valid_zuliprc_but_no_connection(capsys, mocker, minimal_zuliprc,
"Loading with:",
" theme 'zt_dark' specified with no config.",
" autohide setting 'no_autohide' specified with no config.",
" footlinks setting 'enabled' specified with no config.",
" maximum footlinks value '3' specified with no config.",
" color depth setting '256' specified with no config.",
"\x1b[91m",
("Error connecting to Zulip server: {}.\x1b[0m".
Expand Down Expand Up @@ -150,7 +150,7 @@ def test_warning_regarding_incomplete_theme(capsys, mocker, monkeypatch,
" (you could try: {}, {})"
"\x1b[0m".format('a', 'b'),
" autohide setting 'no_autohide' specified with no config.",
" footlinks setting 'enabled' specified with no config.",
" maximum footlinks value '3' specified with no config.",
" color depth setting '256' specified with no config.",
"\x1b[91m",
("Error connecting to Zulip server: {}.\x1b[0m".
Expand Down Expand Up @@ -262,9 +262,103 @@ def test_main_cannot_write_zuliprc_given_good_credentials(
assert lines[-1] == expected_line


@pytest.mark.parametrize('error_code, helper_text', [
(1, ""),
(2, "helper"),
@pytest.fixture
def parameterized_zuliprc(tmpdir):
def func(config):
zuliprc_path = str(tmpdir) + "/zuliprc"
with open(zuliprc_path, "w") as f:
f.write("[api]\n\n") # minimal to avoid Exception
f.write("[zterm]\n")
for key, value in config.items():
f.write(f"{key}={value}\n")
os.chmod(zuliprc_path, 0o600)
return zuliprc_path
return func


@pytest.mark.parametrize("config_key,config_value,footlinks_output", [
("footlinks", "disabled",
" maximum footlinks value '0' "
"specified in zuliprc file from footlinks."),
("footlinks", "enabled",
" maximum footlinks value '3' "
"specified in zuliprc file from footlinks."),
("maximum-footlinks", "3",
" maximum footlinks value '3' specified in zuliprc file."),
("maximum-footlinks", "0",
" maximum footlinks value '0' specified in zuliprc file.")
],
ids=[
"footlinks_disabled",
"footlinks_enabled",
"maximum-footlinks_3",
"maximum-footlinks_0"
])
def test_successful_main_function_with_config(
config_key, config_value,
capsys, mocker, parameterized_zuliprc,
footlinks_output
):
config = {
"theme": "default",
"autohide": "autohide",
"notify": "enabled",
"color-depth": "256"
}
config[config_key] = config_value
zuliprc = parameterized_zuliprc(config)
mocker.patch("zulipterminal.core.Controller.__init__",
return_value=None)
mocker.patch("zulipterminal.core.Controller.main",
return_value=None)
with pytest.raises(SystemExit):
main(["-c", zuliprc])

captured = capsys.readouterr()
lines = captured.out.strip().split("\n")
expected_lines = [
'Loading with:',
" theme 'zt_dark' specified in zuliprc file (by alias 'default').",
" autohide setting 'autohide' specified in zuliprc file.",
footlinks_output,
" color depth setting '256' specified in zuliprc file."
]
assert lines == expected_lines


@pytest.mark.parametrize("zulip_config,err_message", [
({
"footlinks": "enabled",
"maximum-footlinks": "3"
},
"Footlinks property is not allowed alongside maximum-footlinks"
),
({"maximum-footlinks": "-3"},
"Minimum value allowed for maximum-footlinks is 0"
)
])
def test_main_error_with_invalid_zuliprc_options(
parameterized_zuliprc, zulip_config, capsys,
mocker, err_message
):
zuliprc = parameterized_zuliprc(zulip_config)
mocker.patch("zulipterminal.core.Controller.__init__",
return_value=None
)
mocker.patch("zulipterminal.core.Controller.main",
return_value=None)
with pytest.raises(SystemExit) as e:
main(["-c", zuliprc])
assert str(e.value) == "1"
captured = capsys.readouterr()
lines = captured.out.strip()
expected_lines = f"\033[91m{err_message}\033[0m"
assert lines == expected_lines


@pytest.mark.parametrize('error_code,helper_text', [
(0, ""),
(1, "helper")
])
def test_exit_with_error(error_code, helper_text,
capsys, error_message="some text"):
Expand Down
9 changes: 5 additions & 4 deletions tests/core/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ def controller(self, mocker) -> None:
self.in_explore_mode = False
self.autohide = True # FIXME Add tests for no-autohide
self.notify_enabled = False
self.footlinks_enabled = True
result = Controller(self.config_file, self.theme_name, self.theme, 256,
self.maximum_footlinks = 3
result = Controller(self.config_file, self.maximum_footlinks,
self.theme_name, self.theme, 256,
self.in_explore_mode, self.autohide,
self.notify_enabled, self.footlinks_enabled)
self.notify_enabled)
result.view.message_view = mocker.Mock() # set in View.__init__
return result

Expand All @@ -51,7 +52,7 @@ def test_initialize_controller(self, controller, mocker) -> None:
self.view.assert_called_once_with(controller)
self.poll_for_events.assert_called_once_with()
assert controller.theme == self.theme

assert controller.maximum_footlinks == self.maximum_footlinks
assert self.main_loop.call_count == 1
controller.loop.watch_pipe.assert_has_calls([
mocker.call(controller._draw_screen),
Expand Down
15 changes: 8 additions & 7 deletions tests/ui/test_ui_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2073,7 +2073,7 @@ def test_reactions_view(self, message_fixture, to_vary_in_each_message):
)
def test_footlinks_view(self, message_fixture, message_links,
expected_text, expected_attrib):
self.model.controller.footlinks_enabled = True
self.model.controller.maximum_footlinks = 3
msg_box = MessageBox(message_fixture, self.model, None)

footlinks = msg_box.footlinks_view(message_links)
Expand All @@ -2085,16 +2085,17 @@ def test_footlinks_view(self, message_fixture, message_links,
assert footlinks is None
assert not hasattr(footlinks, 'original_widget')

@pytest.mark.parametrize('footlinks_enabled, expected_instance', [
(False, type(None)),
(True, Padding),
@pytest.mark.parametrize('maximum_footlinks, expected_instance', [
(0, type(None)),
(1, Padding),
(3, Padding),
Abhirup-99 marked this conversation as resolved.
Show resolved Hide resolved
])
def test_footlinks_enabled(self, message_fixture, footlinks_enabled,
expected_instance):
def test_footlinks_limit(self, message_fixture, maximum_footlinks,
expected_instance):
message_links = OrderedDict([
('/~https://github.com/zulip/zulip-terminal', ('ZT', 1, True)),
])
self.model.controller.footlinks_enabled = footlinks_enabled
self.model.controller.maximum_footlinks = maximum_footlinks
msg_box = MessageBox(message_fixture, self.model, None)

footlinks = msg_box.footlinks_view(message_links)
Expand Down
4 changes: 2 additions & 2 deletions tests/ui_tools/test_popups.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def mock_external_classes(self, mocker):
theme_name='zt_dark',
color_depth=256,
autohide_enabled=False,
footlink_enabled=True)
maximum_footlinks=3)

@pytest.mark.parametrize('key', {*keys_for_command('GO_BACK'),
*keys_for_command('ABOUT')})
Expand Down Expand Up @@ -177,7 +177,7 @@ def test_feature_level_content(self, mocker, zulip_version):
theme_name='zt_dark',
color_depth=256,
autohide_enabled=False,
footlink_enabled=True)
maximum_footlinks=3)

assert len(about_view.feature_level_content) == (
1 if server_feature_level else 0
Expand Down
37 changes: 33 additions & 4 deletions zulipterminal/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

TRACEBACK_LOG_FILENAME = 'zulip-terminal-tracebacks.log'
API_CALL_LOG_FILENAME = 'zulip-terminal-API-requests.log'
ZULIPRC_CONFIG = 'in zuliprc file'
NO_CONFIG = 'with no config'

# Create a logger for this application
zt_logger = logging.getLogger(__name__)
Expand All @@ -46,6 +48,7 @@
'notify': 'disabled',
'footlinks': 'enabled',
'color-depth': '256',
'maximum-footlinks': '3'
}


Expand Down Expand Up @@ -271,7 +274,6 @@ def parse_zuliprc(zuliprc_str: str) -> Dict[str, Any]:

if 'zterm' in zuliprc:
config = zuliprc['zterm']
ZULIPRC_CONFIG = 'in zuliprc file'
for conf in config:
settings[conf] = (config[conf], ZULIPRC_CONFIG)

Expand Down Expand Up @@ -339,6 +341,27 @@ def main(options: Optional[List[str]]=None) -> None:
else:
theme_to_use = zterm['theme']

if (zterm['footlinks'][1] == ZULIPRC_CONFIG
and zterm['maximum-footlinks'][1] == ZULIPRC_CONFIG):
exit_with_error(
error_message='Footlinks property is not allowed '
'alongside maximum-footlinks')

if (zterm['maximum-footlinks'][1] == ZULIPRC_CONFIG
and int(zterm['maximum-footlinks'][0]) < 0):
exit_with_error(
error_message='Minimum value allowed '
'for maximum-footlinks is 0')

if zterm['footlinks'][1] == ZULIPRC_CONFIG:
if zterm['footlinks'][0] == DEFAULT_SETTINGS['footlinks']:
maximum_footlinks = 3
Abhirup-99 marked this conversation as resolved.
Show resolved Hide resolved
else:
maximum_footlinks = 0

else:
maximum_footlinks = int(zterm['maximum-footlinks'][0])

available_themes = all_themes()
theme_aliases = aliased_themes()
is_valid_theme = (
Expand Down Expand Up @@ -374,16 +397,21 @@ def main(options: Optional[List[str]]=None) -> None:
format(", ".join(complete))))
print(" autohide setting '{}' specified {}."
.format(*zterm['autohide']))
print(" footlinks setting '{}' specified {}."
.format(*zterm['footlinks']))
if zterm['footlinks'][1] == ZULIPRC_CONFIG:
print(
" maximum footlinks value '{}' specified {} from footlinks."
.format(maximum_footlinks, zterm['footlinks'][1]))
else:
print(
" maximum footlinks value '{}' specified {}."
.format(*zterm['maximum-footlinks']))
print(" color depth setting '{}' specified {}."
.format(*zterm['color-depth']))
# For binary settings
# Specify setting in order True, False
valid_settings = {
'autohide': ['autohide', 'no_autohide'],
'notify': ['enabled', 'disabled'],
'footlinks': ['enabled', 'disabled'],
'color-depth': ['1', '16', '256']
}
boolean_settings = dict() # type: Dict[str, bool]
Expand All @@ -407,6 +435,7 @@ def main(options: Optional[List[str]]=None) -> None:
theme_data = THEMES[theme_to_use[0]]

Controller(zuliprc_path,
maximum_footlinks,
theme_to_use[0],
theme_data,
color_depth,
Expand Down
10 changes: 5 additions & 5 deletions zulipterminal/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ class Controller:
the application.
"""

def __init__(self, config_file: str, theme_name: str, theme: ThemeSpec,
color_depth: int, in_explore_mode: bool,
autohide: bool, notify: bool, footlinks: bool) -> None:
def __init__(self, config_file: str, maximum_footlinks: int,
theme_name: str, theme: ThemeSpec, color_depth: int,
in_explore_mode: bool, autohide: bool, notify: bool) -> None:
self.theme_name = theme_name
self.theme = theme
self.color_depth = color_depth
self.in_explore_mode = in_explore_mode
self.autohide = autohide
self.notify_enabled = notify
self.footlinks_enabled = footlinks
self.maximum_footlinks = maximum_footlinks

self._editor = None # type: Optional[Any]

Expand Down Expand Up @@ -231,7 +231,7 @@ def show_about(self) -> None:
server_feature_level=self.model.server_feature_level,
theme_name=self.theme_name, color_depth=self.color_depth,
autohide_enabled=self.autohide,
footlink_enabled=self.footlinks_enabled),
maximum_footlinks=self.maximum_footlinks),
'area:help'
)

Expand Down
6 changes: 5 additions & 1 deletion zulipterminal/ui_tools/boxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -802,14 +802,18 @@ def footlinks_view(
self, message_links: 'OrderedDict[str, Tuple[str, int, bool]]',
) -> Any:
# Return if footlinks are disabled by the user.
if not self.model.controller.footlinks_enabled:
if self.model.controller.maximum_footlinks == 0:
return None

footlinks = []
counter = 0
for link, (text, index, show_footlink) in message_links.items():
if counter == self.model.controller.maximum_footlinks:
break
if not show_footlink:
continue

counter += 1
footlinks.extend([
('msg_link_index', f"{index}:"),
' ',
Expand Down
4 changes: 2 additions & 2 deletions zulipterminal/ui_tools/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ def __init__(self, controller: Any, title: str, *, zt_version: str,
server_version: str,
server_feature_level: Optional[int],
theme_name: str, color_depth: int,
autohide_enabled: bool, footlink_enabled: bool) -> None:
autohide_enabled: bool, maximum_footlinks: int) -> None:
self.feature_level_content = (
[('Feature level', str(server_feature_level))]
if server_feature_level else []
Expand All @@ -1026,7 +1026,7 @@ def __init__(self, controller: Any, title: str, *, zt_version: str,
('Application Configuration', [
('Theme', theme_name),
('Autohide', 'enabled' if autohide_enabled else 'disabled'),
('Footlink', 'enabled' if footlink_enabled else 'disabled'),
('Maximum footlinks', str(maximum_footlinks)),
('Color depth', str(color_depth))])
]

Expand Down