Source code for xonsh.webconfig.routes

import logging
import sys
from urllib import parse

from xonsh.built_ins import XonshSession
from xonsh.environ import Env

from . import tags as t
from . import xonsh_data
from .file_writes import insert_into_xonshrc


[docs] class Routes: path: str registry: "dict[str, type[Routes]]" = {} navbar = False nav_title: "str|None" = None err_msgs: "list" = [] """session storage for error messages""" def __init__( self, url: "parse.ParseResult", params: "dict[str, list[str]]", xsh: "XonshSession", ): self.url = url self.params = params self.env: Env = xsh.env self.xsh = xsh def __init_subclass__(cls, **kwargs): cls.registry[cls.path] = cls
[docs] def err(self, msg: str): html = xonsh_data.rst_to_html(msg) tree = t.etree.fromstring(html) self.err_msgs.append(tree)
_external_links = [ ("Docs", "https://xon.sh/dev/contents.html"), ("Xontribs", "https://github.com/topics/xontrib"), ("Code", "https://github.com/xonsh/xonsh"), ("Sponsor", "https://github.com/sponsors/xonsh"), ]
[docs] def get_err_msgs(self): if not self.err_msgs: return for msg in self.err_msgs: yield t.alert("alert-danger")[msg] self.err_msgs.clear()
[docs] def get_sel_url(self, name): params = parse.urlencode({"selected": name}) return self.path + "?" + params
[docs] @staticmethod def get_display(display): try: display = t.etree.fromstring(f"<div>{display}</div>") except Exception as ex: logging.error(f"Failed to parse color-display {ex!r}. {display!r}") display = t.pre()[display] return display
[docs] def update_rc(self, **kwargs): # todo: handle updates and deletion as well insert_into_xonshrc(kwargs)
[docs] class ColorsPage(Routes): path = "/" nav_title = "Colors" def __init__(self, **kwargs): super().__init__(**kwargs) self.colors = dict(xonsh_data.render_colors()) self.var_name = "XONSH_COLOR_STYLE"
[docs] def to_card(self, name: str, display: str): return t.card()[ t.card_body()[ t.card_title()[ t.a("stretched-link", href=self.get_sel_url(name))[name] ], self.get_display(display), ] ]
[docs] def get_cols(self): for name, display in self.colors.items(): yield t.col_sm()[self.to_card(name, display),]
def _get_selected_header(self): selected = self.params.get("selected") current = self.env.get(self.var_name) if selected and selected != current: name = selected[0] # update env-variable form = t.inline_form(method="post")[ t.btn_primary("ml-2", "p-1", type="submit", name=self.var_name)[ f"Update ${self.var_name}", ], ] return (f"Selected: {name}", form), name return (f"Current: {current}",), current
[docs] def get_selected(self): header, name = self._get_selected_header() name = name if name in self.colors else "default" display = self.colors[name] card = t.card()[ t.card_header()[header], t.card_body()[self.get_display(display)], ] return t.row()[t.col()[card],]
[docs] def get(self): # banner yield self.get_selected() yield t.br() yield t.br() # rest cols = list(self.get_cols()) yield t.row()[cols]
[docs] def post(self, _): selected = self.params.get("selected") if selected: self.env[self.var_name] = selected[0] self.update_rc(color=selected[0])
[docs] class PromptsPage(Routes): path = "/prompts" nav_title = "Prompts" def __init__(self, **kwargs): super().__init__(**kwargs) prompts = xonsh_data.render_prompts(self.env) self.current = next(prompts) self.prompts = dict(prompts) self.card_width = self.prompts.pop("__max_width__", 40) self.var_name = "PROMPT" # todo: support updating RIGHT_PROMPT, BOTTOM_TOOLBAR
[docs] def to_card(self, name: str, display: str): return t.card()[ t.card_body()[ t.card_title()[ t.a("stretched-link", href=self.get_sel_url(name))[name] ], self.get_display(display), ] ]
def _get_selected_header(self): ps_names = self.params.get("selected") if ps_names: name = ps_names[0] if name in self.prompts: return f"Selected: {name}", name return "Current: ", None
[docs] def get_selected(self): header, cur_sel = self._get_selected_header() if cur_sel is None: prompt = self.current["value"] display = self.current["display"] else: cont = self.prompts[cur_sel] prompt: str = cont["value"] display = cont["display"] # update env-variable txt_area = t.textarea( "form-control", name=self.var_name, rows=str(len(prompt.splitlines())), )[prompt] card = t.card()[ t.card_header()[header], t.card_body()[ t.card_title()["Edit"], txt_area, t.br(), t.card_title()["Preview"], t.p("text-muted")[ "It is not a live preview. `Set` to get the updated view." ], self.get_display(display), ], t.card_footer("py-1")[t.btn_primary("py-1", type="submit")["Set",],], ] return t.row()[t.col()[t.form(method="post")[card]],]
[docs] def get_cols(self): style = f"min-width: {self.card_width}ch" for name, prompt in self.prompts.items(): yield t.div("col-auto", style=style)[self.to_card(name, prompt["display"]),]
[docs] def get(self): # banner yield self.get_selected() yield t.br() yield t.br() # rest cols = list(self.get_cols()) yield t.row()[cols]
[docs] def post(self, data: dict[str, str]): if prompt := data.get(self.var_name): prompt = prompt.replace("\r", "") self.env[self.var_name] = prompt self.update_rc(prompt=prompt)
[docs] class XontribsPage(Routes): path = "/xontribs" nav_title = "Xontribs" def __init__(self, **kwargs): super().__init__(**kwargs) self.xontribs = dict(xonsh_data.render_xontribs())
[docs] @staticmethod def mod_name(name): return f"xontrib.{name}"
[docs] @staticmethod def is_loaded(name): return XontribsPage.mod_name(name) in sys.modules
[docs] def xontrib_card(self, name, data): from xonsh.xontribs import find_xontrib title = t.a(href=data["url"])[name] if find_xontrib(name): act_label = "Add" if self.is_loaded(name): act_label = "Remove" action = t.inline_form(method="post")[ t.btn_primary("ml-2", "p-1", type="submit", name=name)[act_label,], ] else: title = title("stretched-link") # add class action = "" return t.card()[ t.card_header()[title, action], t.card_body()[self.get_display(data["display"]),], ]
[docs] def get(self): yield t.card()[ t.card_body()[ t.card_title()["Popular xontrib sources"], t.card_body()[ t.li()[ t.a(href="https://github.com/topics/xontrib")[ "Xontribs on Github" ] ], t.li()[ t.a(href="https://github.com/xonsh/awesome-xontribs")[ "Awesome xontribs" ] ], t.li()[ t.a( href="https://xon.sh/api/_autosummary/xontribs/xontrib.html" )["Core xontribs"] ], t.li()[ t.a(href="https://github.com/xonsh/xontrib-template")[ "Create a xontrib step by step from template" ] ], ], ] ] yield t.br() for name, data in self.xontribs.items(): yield t.row()[t.col()[self.xontrib_card(name, data),]] yield t.br()
[docs] def post(self, data: dict[str, str]): if not data: return name = list(data)[0] if self.is_loaded(name): # todo: update rc file del sys.modules[self.mod_name(name)] else: from xonsh.xontribs import xontribs_load _, err, _ = xontribs_load([name]) if err: self.err(err) else: self.update_rc(xontribs=[name])
[docs] class EnvVariablesPage(Routes): path = "/vars" nav_title = "Variables"
[docs] def get_header(self): yield t.tr()[ t.th("text-right")["Name"], t.th()["Value"], ]
[docs] def get_rows(self): for name in sorted(self.env.keys()): if not self.env.is_configurable(name): continue value = self.env[name] envvar = self.env.get_docs(name) html = xonsh_data.rst_to_html(envvar.doc) yield t.tr()[ t.td("text-right")[str(name)], t.td()[ t.p()[repr(value)], t.small()[self.get_display(html)], ], ]
[docs] def get_table(self): rows = list(self.get_rows()) yield t.tbl("table-striped")[ self.get_header(), rows, ]
[docs] def get(self): yield t.div("table-responsive")[self.get_table()]
[docs] class AliasesPage(Routes): path = "/alias" nav_title = "Aliases"
[docs] def get_header(self): yield t.tr()[ t.th("text-right")["Name"], t.th()["Value"], ]
[docs] def get_rows(self): if not self.xsh.aliases: return for name in sorted(self.xsh.aliases.keys()): alias = self.xsh.aliases[name] if callable(alias): continue # todo: # 1. do not edit default aliases as well # 2. way to update string aliases yield t.tr()[ t.td("text-right")[str(name)], t.td()[t.p()[repr(alias)],], ]
[docs] def get_table(self): rows = list(self.get_rows()) yield t.tbl("table-sm", "table-striped")[ self.get_header(), rows, ]
[docs] def get(self): yield t.card()[ t.card_body()[ t.card_title()["Docs"], t.card_body()[ t.li()[t.a(href="https://xon.sh/tutorial.html")["Tutorial"]], t.li()[ t.a(href="https://xon.sh/callable_aliases.html")[ "Callable Aliases" ] ], ], ] ] yield t.br() yield t.div("table-responsive")[self.get_table()]