# -*- coding: utf-8 -*- # # Copyright (C) 2014 - 2019 Stefan Wold # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # (This script requires WeeChat 0.4.3 or higher). # # WeeChat script for responsive layout based on terminal height and width. # # # Source and changes available on GitHUB: https://github.com/Ratler/ratlers-weechat-scripts # # Commands: # /rlayout from __future__ import print_function SCRIPT_NAME = "responsive_layout" SCRIPT_AUTHOR = "Stefan Wold " SCRIPT_VERSION = "0.8" SCRIPT_LICENSE = "GPL3" SCRIPT_DESC = "Responsive layout will automatically apply layouts based on the terminals current size." SCRIPT_COMMAND = "rlayout" SETTINGS = { "default_nicklist": ("on", "Global setting to always show nicklist when layout switches."), "debug": ("off", "Script debug output"), } LAYOUT_LIST = [] import_ok = True try: import weechat except ImportError: print("This script must be run under WeeChat.") import_ok = False try: import re from operator import itemgetter except ImportError as err: print("Missing module(s) for %s: %s" % (SCRIPT_NAME, err)) import_ok = False def _print(message, buf=""): weechat.prnt(buf, "%s: %s" % (SCRIPT_NAME, message)) def _debug(message, buf=""): if weechat.config_get_plugin('debug') == 'on': weechat.prnt(buf, "+++ %s (debug): %s" % (SCRIPT_NAME, message)) def responsive_cb(data, signal, signal_data): term_height = int(weechat.info_get("term_height", "")) term_width = int(weechat.info_get("term_width", "")) try: apply_layout = None for layout, width, height in LAYOUT_LIST: if term_height <= int(height) or term_width <= int(width): apply_layout = layout break if apply_layout is None: # Always apply the last layout if term width/height is larger than configured layouts apply_layout = LAYOUT_LIST[-1][0] if layout_exist(apply_layout) and not layout_current(apply_layout): _print("Applying layout %s" % apply_layout) weechat.command("", "/layout apply %s" % apply_layout) toggle_nick_list(apply_layout) weechat.bar_item_update("rlayout") except ValueError: _print("Height or width is not in number form, ignoring.") return weechat.WEECHAT_RC_OK def layout_current(layout): infolist = weechat.infolist_get("layout", "", "") current = False while weechat.infolist_next(infolist): if weechat.infolist_integer(infolist, "current_layout") == 1 and \ weechat.infolist_string(infolist, "name") == layout: current = True break weechat.infolist_free(infolist) return current def layout_exist(layout): infolist = weechat.infolist_get("layout", "", "") found = False while weechat.infolist_next(infolist): if layout == weechat.infolist_string(infolist, "name"): found = True break weechat.infolist_free(infolist) return found def toggle_nick_list(layout): """ Check configuration whether nick list bar should be on or off for the provided layout. """ value = weechat.config_get_plugin("layout.%s.nicklist" % layout) if value == "": value = weechat.config_get_plugin("default_nicklist") if value == "on": weechat.command("", "/bar show nicklist") elif value == "off": weechat.command("", "/bar hide nicklist") def rlayouts_list(): """ Return a list of configured rlayouts. """ layouts = [] pattern = re.compile(r"^plugins\.var\.python\.%s\.layout\.(.+)\." % SCRIPT_NAME) infolist = weechat.infolist_get("option", "", "plugins.var.python.%s.layout.*" % SCRIPT_NAME) while weechat.infolist_next(infolist): layout = re.search(pattern, weechat.infolist_string(infolist, "full_name")).groups() if layout[0] not in layouts: layouts.append(layout[0]) weechat.infolist_free(infolist) return layouts def update_layout_list(): """ Updates global LAYOUT_LIST with a sorted array containing layout tuples, ie (layout_name, width, height) """ global LAYOUT_LIST layout_tuples = [] for layout in rlayouts_list(): width = weechat.config_get_plugin("layout.%s.width" % layout) height = weechat.config_get_plugin("layout.%s.height" % layout) if width is not "" and height is not "": layout_tuples.append((layout, int(width), int(height))) layout_tuples.sort(key=itemgetter(1, 2)) _debug("update_layout_list(%s)" % layout_tuples) LAYOUT_LIST = layout_tuples def rlayout_cmd_cb(data, buffer, args): """ Callback for /rlayout command. """ if args == "": weechat.command("", "/help %s" % SCRIPT_COMMAND) return weechat.WEECHAT_RC_OK argv = args.strip().split(" ", 1) if len(argv) == 0: return weechat.WEECHAT_RC_OK short_cmds = ["list", "terminal"] if argv[0] not in short_cmds and len(argv) < 2: _print("Too few arguments for option '%s'." % argv[0]) return weechat.WEECHAT_RC_OK if argv[0] == "size": try: layout, width, height = argv[1].split(" ") if layout_exist(layout): weechat.config_set_plugin("layout.%s.width" % layout, width) weechat.config_set_plugin("layout.%s.height" % layout, height) update_layout_list() else: _print("Layout '%s' doesn't exist, see /help layout to create one." % layout) except ValueError: _print("Too few arguments for option '%s'" % argv[0]) elif argv[0] == "nicklist": try: layout, nicklist = argv[1].split(" ") if layout_exist(layout): if nicklist == "on" or nicklist == "off": weechat.config_set_plugin("layout.%s.nicklist" % layout, nicklist) else: _print("Invalid argument '%s' for option '%s'." % (nicklist, argv[0])) else: _print("Layout '%s' doesn't exist, see /help layout to create one." % layout) except ValueError: _print("Too few arguments for option '%s'" % argv[0]) elif argv[0] == "default_nicklist" or argv[0] == "debug": if argv[1] == "on" or argv[1] == "off": weechat.config_set_plugin(argv[0], argv[1]) else: _print("Invalid argument '%s' for option '%s'" % (argv[1], argv[0])) elif argv[0] == "remove": if argv[1] in rlayouts_list(): for option in ["width", "height", "nicklist"]: weechat.config_unset_plugin("layout.%s.%s" % (argv[1], option)) _print("Removed rlayout '%s'" % argv[1]) else: _print("Could not remove '%s', rlayout not found." % argv[1]) elif argv[0] == "list": if len(rlayouts_list()) == 0: _print("No configuration set.") else: for rlayout in rlayouts_list(): width = weechat.config_get_plugin("layout.%s.width" % rlayout) height = weechat.config_get_plugin("layout.%s.height" % rlayout) nicklist = weechat.config_get_plugin("layout.%s.nicklist" % rlayout) msg = "[%s] width: %s, height: %s" % (rlayout, width, height) if nicklist is not "": msg += ", nicklist: %s" % nicklist _print(msg) elif argv[0] == "terminal": term_height = int(weechat.info_get("term_height", "")) term_width = int(weechat.info_get("term_width", "")) _print("Current terminal width x height is: %s x %s" % (term_width, term_height)) return weechat.WEECHAT_RC_OK def rlayout_bar_cb(data, item, window): infolist = weechat.infolist_get("layout", "", "") layout = None while weechat.infolist_next(infolist): if weechat.infolist_integer(infolist, "current_layout") == 1: layout = weechat.infolist_string(infolist, "name") break weechat.infolist_free(infolist) if layout is None: return "" else: term_height = int(weechat.info_get("term_height", "")) term_width = int(weechat.info_get("term_width", "")) return "%s (%sx%s)" % (layout, term_width, term_height) def rlayout_completion_bool_cb(data, completion_item, buffer, completion): for bool in ("on", "off"): weechat.hook_completion_list_add(completion, bool, 0, weechat.WEECHAT_LIST_POS_SORT) return weechat.WEECHAT_RC_OK def rlayout_completion_layout_list_cb(data, completion_item, buffer, completion): for rlayout in rlayouts_list(): weechat.hook_completion_list_add(completion, rlayout, 0, weechat.WEECHAT_LIST_POS_SORT) return weechat.WEECHAT_RC_OK def config_cb(data, option, value): update_layout_list() return weechat.WEECHAT_RC_OK if __name__ == "__main__" and import_ok: if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""): version = weechat.info_get("version_number", "") or 0 if int(version) < 0x00040300: _print("Requires WeeChat >= 0.4.3 for terminal height and width support.") weechat.command("", "/wait 1ms /python unload %s" % SCRIPT_NAME) weechat.hook_command(SCRIPT_COMMAND, "WeeChat responsive layout configuration", "size || nicklist || default_nicklist " " || remove || list || terminal || debug ", " size: set max size (width and height) for layout to be automatically applied\n" " nicklist: show or hide nicklist bar when layout is automatically applied\n" "default_nicklist: default show or hide nicklist bar if not configured per layout\n" " remove: remove settings for responsive layout\n" " list: list current configuration\n" " terminal: list current terminal width and height\n" " debug: print script debug output\n\n" "To get current layout and terminal dimensions in your bar, use 'rlayout' bar item.", "size %(layouts_names)" " || nicklist %(layouts_names) %(rlayout_bool_value)" " || default_nicklist %(rlayout_bool_value)" " || remove %(rlayouts_names)" " || list" " || terminal" " || debug %(rlayout_bool_value)", "rlayout_cmd_cb", "") # Default settings for option, default_value in SETTINGS.items(): if weechat.config_get_plugin(option) == "": weechat.config_set_plugin(option, default_value[0]) weechat.config_set_desc_plugin(option, '%s (default: %s)' % (default_value[1], default_value[0])) weechat.hook_completion("rlayout_bool_value", "list of bool values", "rlayout_completion_bool_cb", "") weechat.hook_completion("rlayouts_names", "list of rlayouts", "rlayout_completion_layout_list_cb", "") weechat.hook_config("plugins.var.python.responsive_layout.layout.*", "config_cb", "") weechat.bar_item_new("rlayout", "rlayout_bar_cb", "") update_layout_list() hook = weechat.hook_signal("signal_sigwinch", "responsive_cb", "")