From 62f260def129baf3b211da3843c5e30d0491a31d Mon Sep 17 00:00:00 2001 From: "kujiu (@uberwald)" Date: Sat, 30 Sep 2023 01:02:41 +0200 Subject: [PATCH] IPython prompt --- README.rst | 61 +--------- pygments_nightfox_style/__init__.py | 19 ++- pygments_nightfox_style/ipython_prompt.py | 142 ++++++++++++++++++++++ pyproject.toml | 3 +- 4 files changed, 164 insertions(+), 61 deletions(-) create mode 100644 pygments_nightfox_style/ipython_prompt.py diff --git a/README.rst b/README.rst index c064ad3..115cafa 100644 --- a/README.rst +++ b/README.rst @@ -13,62 +13,7 @@ IPython configuration: .. code:: python - from IPython.terminal.prompts import Prompts, RichPromptDisplayHook - from pygments.token import Token - from prompt_toolkit.enums import EditingMode - from platform import python_version - import os - import socket - import subprocess + from pygments_nightfox_style.ipython_prompt import NightfoxPrompts - class NightfoxPrompts(Prompts): - def vi_mode(self): - if (getattr(self.shell.pt_app, 'editing_mode', None) == EditingMode.VI - and self.shell.prompt_includes_vi_mode): - mode = str(self.shell.pt_app.app.vi_state.input_mode) - if "INSERT" in mode: - return 'I' - if "NAV" in mode: - return 'N' - if "REPLACE_SINGLE" in mode: - return 'r' - if "REPLACE" in mode: - return 'R' - return 'E' # Emacs mode - - def in_prompt_tokens(self): - git_branch = "" - try: - git_branch = subprocess.check_output( - ["git", "branch", "--show-current"], stderr=subprocess.DEVNULL - ) - if git_branch: - git_branch = git_branch.decode("utf-8").replace("\n", "") - except subprocess.CalledProcessError: - pass - - git_branch = str(git_branch) - - venv = (os.environ.get("VIRTUAL_ENV") or "").split("/")[-1] - - return [ - (Token.IPython.Prompt.Login, os.getlogin()), - (Token.IPython.Prompt.Login.Sep, ''), - (Token.IPython.Prompt.Host, socket.gethostname()), - (Token.IPython.Prompt.Host.Sep, ''), - (Token.IPython.Prompt.Venv, venv), - (Token.IPython.Prompt.Venv.Sep, ''), - (Token.IPython.Prompt.Version, ' ' + python_version()), - (Token.IPython.Prompt.Version.Sep, ''), - (Token, '\n'), - (Token.IPython.Prompt.Cwd, os.getcwd()), - (Token.IPython.Prompt.Cwd.Sep, ''), - (Token.IPython.Prompt.Vcs, str(' ') + git_branch if git_branch else ''), - (Token.IPython.Prompt.Vcs.Sep, ''), - (Token, '\n'), - (Token.IPython.Prompt.Mode, self.vi_mode()), - (Token.IPython.Prompt.Mode.Sep, ' '), - ] - - def out_prompt_tokens(self): - return [] + c = get_config() + c.TerminalInteractiveShell.prompts_class = NightfoxPrompts diff --git a/pygments_nightfox_style/__init__.py b/pygments_nightfox_style/__init__.py index 55b7633..7d7915d 100644 --- a/pygments_nightfox_style/__init__.py +++ b/pygments_nightfox_style/__init__.py @@ -180,14 +180,29 @@ def get_styles(background_color: str) -> Dict[Any, str]: Token.IPython.Prompt.Host.Sep: NFOX_BLUE + " bg:" + NFOX_FG3, Token.IPython.Prompt.Venv: NFOX_BG0 + " bg:" + NFOX_FG3, Token.IPython.Prompt.Venv.Sep: NFOX_FG3 + " bg:" + NFOX_GREEN, - Token.IPython.Prompt.Version: NFOX_BG0 + " bg:" + NFOX_GREEN, - Token.IPython.Prompt.Version.Sep: "bg: " + NFOX_GREEN, + Token.IPython.Prompt.Venv.Error.Sep: NFOX_FG3 + " bg:" + NFOX_RED, + Token.IPython.Prompt.Status: NFOX_BG0 + " bg:" + NFOX_GREEN, + Token.IPython.Prompt.Status.Sep: "bg: " + NFOX_GREEN, + Token.IPython.Prompt.Status.Error: NFOX_BG0 + " bg:" + NFOX_RED, + Token.IPython.Prompt.Status.Error.Sep: "bg: " + NFOX_RED, Token.IPython.Prompt.Cwd: NFOX_BG0 + " bg:" + NFOX_GREEN, Token.IPython.Prompt.Cwd.Sep: NFOX_GREEN + " bg:" + NFOX_BG2, + Token.IPython.Prompt.Cwd.Root: NFOX_BG0 + " bg:" + NFOX_RED, + Token.IPython.Prompt.Cwd.Root.Sep: NFOX_RED + " bg:" + NFOX_BG2, Token.IPython.Prompt.Vcs: NFOX_ORANGE + " bg:" + NFOX_BG2, Token.IPython.Prompt.Vcs.Sep: "bg: " + NFOX_BG2, Token.IPython.Prompt.Mode: NFOX_BG0 + " bg:" + NFOX_GREEN, Token.IPython.Prompt.Mode.Sep: "bg: " + NFOX_GREEN, + Token.IPython.Prompt.Mode.Nav: NFOX_BG0 + " bg:" + NFOX_RED, + Token.IPython.Prompt.Mode.Nav.Sep: "bg: " + NFOX_RED, + Token.IPython.Prompt.Mode.Insert: NFOX_BG0 + " bg:" + NFOX_YELLOW, + Token.IPython.Prompt.Mode.Insert.Sep: "bg: " + NFOX_YELLOW, + Token.IPython.Prompt.Mode.Replace: NFOX_BG0 + " bg:" + NFOX_BLUE, + Token.IPython.Prompt.Mode.Replace.Sep: "bg: " + NFOX_BLUE, + Token.IPython.Prompt.Mode.ReplaceOne: NFOX_BG0 + " bg:" + NFOX_CYAN, + Token.IPython.Prompt.Mode.ReplaceOne.Sep: "bg: " + NFOX_CYAN, + Token.IPython.Prompt.Mode.Visual: NFOX_BG0 + " bg:" + NFOX_MAGENTA, + Token.IPython.Prompt.Mode.Visual.Sep: "bg: " + NFOX_MAGENTA, } class NightfoxStyle(Style): diff --git a/pygments_nightfox_style/ipython_prompt.py b/pygments_nightfox_style/ipython_prompt.py new file mode 100644 index 0000000..d559fae --- /dev/null +++ b/pygments_nightfox_style/ipython_prompt.py @@ -0,0 +1,142 @@ + +from IPython.terminal.prompts import Prompts +from IPython.core.getipython import get_ipython +from pygments.token import Token +from prompt_toolkit.enums import EditingMode +from platform import python_version +import os +import socket +import subprocess +import sys + +from typing_extensions import override +from typing import List, Any, Tuple + +TOKENS_MODE = { + 'V': ( + Token.IPython.Prompt.Mode.Visual, + Token.IPython.Prompt.Mode.Visual.Sep, + Token.IPython.Prompt.Mode.Visual.Sep.Root, + ), + 'I': ( + Token.IPython.Prompt.Mode.Insert, + Token.IPython.Prompt.Mode.Insert.Sep, + Token.IPython.Prompt.Mode.Insert.Sep.Root, + ), + 'N': ( + Token.IPython.Prompt.Mode.Nav, + Token.IPython.Prompt.Mode.Nav.Sep, + Token.IPython.Prompt.Mode.Nav.Sep.Root, + ), + 'R': ( + Token.IPython.Prompt.Mode.Replace, + Token.IPython.Prompt.Mode.Replace.Sep, + Token.IPython.Prompt.Mode.Replace.Sep.Root, + ), + 'r': ( + Token.IPython.Prompt.Mode.ReplaceOne, + Token.IPython.Prompt.Mode.ReplaceOne.Sep, + Token.IPython.Prompt.Mode.ReplaceOne.Sep.Root, + ), + 'E': ( + Token.IPython.Prompt.Mode, + Token.IPython.Prompt.Mode.Sep, + Token.IPython.Prompt.Mode.Sep.Root, + ) +} + +class NightfoxPrompts(Prompts): + + @override + def vi_mode(self) -> str: + if (getattr(self.shell.pt_app, 'editing_mode', None) == EditingMode.VI + and self.shell.prompt_includes_vi_mode): + mode = str(self.shell.pt_app.app.vi_state.input_mode) + if "VISUAL" in mode: + return 'V' + if "INSERT" in mode: + return 'I' + if "NAV" in mode: + return 'N' + if "REPLACE_SINGLE" in mode: + return 'r' + if "REPLACE" in mode: + return 'R' + return 'E' # Emacs mode + + @override + def in_prompt_tokens(self) -> List[Tuple[Any, Any]]: + git_branch = "" + try: + git_branch = subprocess.check_output( + ["git", "branch", "--show-current"], stderr=subprocess.DEVNULL + ) + if git_branch: + git_branch = git_branch.decode("utf-8").replace("\n", "") + except subprocess.CalledProcessError: + pass + + git_branch = str(git_branch) + + cwd = str(os.getcwd()) + term_width = int(os.get_terminal_size().columns) + + diff_width = term_width - len(cwd) - len(git_branch) - 4 + if diff_width < 0 and diff_width > -1 - len(cwd): + cwd = '…' + cwd[1-diff_width:] + + venv = (os.environ.get("VIRTUAL_ENV") or "").split("/")[-1] + if venv: + venv += '|' + + vi_mode = self.vi_mode() + login = os.getlogin() + token_cwd = Token.IPython.Prompt.Cwd + token_cwd_sep = Token.IPython.Prompt.Cwd.Sep + token_mode = TOKENS_MODE[vi_mode][0] + token_mode_sep = TOKENS_MODE[vi_mode][1] + token_status = Token.IPython.Prompt.Status + token_status_sep = Token.IPython.Prompt.Status.Sep + token_venv_sep = Token.IPython.Prompt.Venv.Sep + + ip = get_ipython() + last_error = 'NoneType' + if ip and ip.last_execution_result: + last_error = type( + ip.last_execution_result.error_in_exec + ).__name__ + if last_error == 'NoneType': + last_error = '✔' + else: + last_error = '✗' + last_error + token_status = Token.IPython.Prompt.Status.Error + token_status_sep = Token.IPython.Prompt.Status.Error.Sep + token_venv_sep = Token.IPython.Prompt.Venv.Error.Sep + + if login == 'root': + token_cwd = Token.IPython.Prompt.Cwd.Root + token_cwd_sep = Token.IPython.Prompt.Cwd.Root.Sep + token_mode_sep = TOKENS_MODE[vi_mode][2] + + return [ + (Token.IPython.Prompt.Login, login), + (Token.IPython.Prompt.Login.Sep, ''), + (Token.IPython.Prompt.Host, socket.gethostname()), + (Token.IPython.Prompt.Host.Sep, ''), + (Token.IPython.Prompt.Venv, venv + ' ' + python_version()), + (token_venv_sep, ''), + (token_status, last_error), + (token_status_sep, ''), + (Token, '\n'), + (token_cwd, cwd), + (token_cwd_sep if login=='root' else Token.IPython.Prompt.Cwd.Sep, ''), + (Token.IPython.Prompt.Vcs, str(' ') + git_branch if git_branch else ''), + (Token.IPython.Prompt.Vcs.Sep, ''), + (Token, '\n'), + (token_mode, vi_mode), + (token_mode_sep, ''), + ] + + @override + def out_prompt_tokens(self) -> List[Tuple[Any, Any]]: + return [] diff --git a/pyproject.toml b/pyproject.toml index c3ca6a2..903d669 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,8 @@ name = "pygments_nightfox_style" version = "1.0.0" requires-python = ">=3.8" dependencies = [ - "pygments" + "pygments", + "typing_extensions" ] license = {text = "MIT"} authors = [