batrachian-toad 0.5.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. batrachian_toad-0.5.22.dist-info/METADATA +197 -0
  2. batrachian_toad-0.5.22.dist-info/RECORD +120 -0
  3. batrachian_toad-0.5.22.dist-info/WHEEL +4 -0
  4. batrachian_toad-0.5.22.dist-info/entry_points.txt +2 -0
  5. batrachian_toad-0.5.22.dist-info/licenses/LICENSE +661 -0
  6. toad/__init__.py +46 -0
  7. toad/__main__.py +4 -0
  8. toad/_loop.py +86 -0
  9. toad/about.py +90 -0
  10. toad/acp/agent.py +671 -0
  11. toad/acp/api.py +47 -0
  12. toad/acp/encode_tool_call_id.py +12 -0
  13. toad/acp/messages.py +138 -0
  14. toad/acp/prompt.py +54 -0
  15. toad/acp/protocol.py +426 -0
  16. toad/agent.py +62 -0
  17. toad/agent_schema.py +70 -0
  18. toad/agents.py +45 -0
  19. toad/ansi/__init__.py +1 -0
  20. toad/ansi/_ansi.py +1612 -0
  21. toad/ansi/_ansi_colors.py +264 -0
  22. toad/ansi/_control_codes.py +37 -0
  23. toad/ansi/_keys.py +251 -0
  24. toad/ansi/_sgr_styles.py +64 -0
  25. toad/ansi/_stream_parser.py +418 -0
  26. toad/answer.py +22 -0
  27. toad/app.py +557 -0
  28. toad/atomic.py +37 -0
  29. toad/cli.py +257 -0
  30. toad/code_analyze.py +28 -0
  31. toad/complete.py +34 -0
  32. toad/constants.py +58 -0
  33. toad/conversation_markdown.py +19 -0
  34. toad/danger.py +371 -0
  35. toad/data/agents/ampcode.com.toml +51 -0
  36. toad/data/agents/augmentcode.com.toml +40 -0
  37. toad/data/agents/claude.com.toml +41 -0
  38. toad/data/agents/docker.com.toml +59 -0
  39. toad/data/agents/geminicli.com.toml +28 -0
  40. toad/data/agents/goose.ai.toml +51 -0
  41. toad/data/agents/inference.huggingface.co.toml +33 -0
  42. toad/data/agents/kimi.com.toml +35 -0
  43. toad/data/agents/openai.com.toml +53 -0
  44. toad/data/agents/opencode.ai.toml +61 -0
  45. toad/data/agents/openhands.dev.toml +44 -0
  46. toad/data/agents/stakpak.dev.toml +61 -0
  47. toad/data/agents/vibe.mistral.ai.toml +27 -0
  48. toad/data/agents/vtcode.dev.toml +62 -0
  49. toad/data/images/frog.png +0 -0
  50. toad/data/sounds/turn-over.wav +0 -0
  51. toad/db.py +5 -0
  52. toad/dec.py +332 -0
  53. toad/directory.py +234 -0
  54. toad/directory_watcher.py +96 -0
  55. toad/fuzzy.py +140 -0
  56. toad/gist.py +2 -0
  57. toad/history.py +138 -0
  58. toad/jsonrpc.py +576 -0
  59. toad/menus.py +14 -0
  60. toad/messages.py +74 -0
  61. toad/option_content.py +51 -0
  62. toad/os.py +0 -0
  63. toad/path_complete.py +145 -0
  64. toad/path_filter.py +124 -0
  65. toad/paths.py +71 -0
  66. toad/pill.py +23 -0
  67. toad/prompt/extract.py +19 -0
  68. toad/prompt/resource.py +68 -0
  69. toad/protocol.py +28 -0
  70. toad/screens/action_modal.py +94 -0
  71. toad/screens/agent_modal.py +172 -0
  72. toad/screens/command_edit_modal.py +58 -0
  73. toad/screens/main.py +192 -0
  74. toad/screens/permissions.py +390 -0
  75. toad/screens/permissions.tcss +72 -0
  76. toad/screens/settings.py +254 -0
  77. toad/screens/settings.tcss +101 -0
  78. toad/screens/store.py +476 -0
  79. toad/screens/store.tcss +261 -0
  80. toad/settings.py +354 -0
  81. toad/settings_schema.py +318 -0
  82. toad/shell.py +263 -0
  83. toad/shell_read.py +42 -0
  84. toad/slash_command.py +34 -0
  85. toad/toad.tcss +752 -0
  86. toad/version.py +80 -0
  87. toad/visuals/columns.py +273 -0
  88. toad/widgets/agent_response.py +79 -0
  89. toad/widgets/agent_thought.py +41 -0
  90. toad/widgets/command_pane.py +224 -0
  91. toad/widgets/condensed_path.py +93 -0
  92. toad/widgets/conversation.py +1626 -0
  93. toad/widgets/danger_warning.py +65 -0
  94. toad/widgets/diff_view.py +709 -0
  95. toad/widgets/flash.py +81 -0
  96. toad/widgets/future_text.py +126 -0
  97. toad/widgets/grid_select.py +223 -0
  98. toad/widgets/highlighted_textarea.py +180 -0
  99. toad/widgets/mandelbrot.py +294 -0
  100. toad/widgets/markdown_note.py +13 -0
  101. toad/widgets/menu.py +147 -0
  102. toad/widgets/non_selectable_label.py +5 -0
  103. toad/widgets/note.py +18 -0
  104. toad/widgets/path_search.py +381 -0
  105. toad/widgets/plan.py +180 -0
  106. toad/widgets/project_directory_tree.py +74 -0
  107. toad/widgets/prompt.py +741 -0
  108. toad/widgets/question.py +337 -0
  109. toad/widgets/shell_result.py +35 -0
  110. toad/widgets/shell_terminal.py +18 -0
  111. toad/widgets/side_bar.py +74 -0
  112. toad/widgets/slash_complete.py +211 -0
  113. toad/widgets/strike_text.py +66 -0
  114. toad/widgets/terminal.py +526 -0
  115. toad/widgets/terminal_tool.py +338 -0
  116. toad/widgets/throbber.py +90 -0
  117. toad/widgets/tool_call.py +303 -0
  118. toad/widgets/user_input.py +23 -0
  119. toad/widgets/version.py +5 -0
  120. toad/widgets/welcome.py +31 -0
@@ -0,0 +1,35 @@
1
+ # Schema defined in agent_schema.py
2
+ # https://github.com/MoonshotAI/kimi-cli
3
+
4
+ identity = "kimi.com"
5
+ name = "Kimi CLI"
6
+ short_name = "kimi"
7
+ url = "https://www.kimi.com/"
8
+ protocol = "acp"
9
+ author_name = "Moonshot AI"
10
+ author_url = "https://www.kimi.com/"
11
+ publisher_name = "Will McGugan"
12
+ publisher_url = "https://willmcgugan.github.io/"
13
+ type = "coding"
14
+ description = "Kimi CLI is a new CLI agent that can help you with your software development tasks and terminal operations."
15
+ tags = []
16
+ run_command."*" = "kimi --acp"
17
+
18
+ help = '''
19
+ # Kimi CLI
20
+
21
+ Kimi CLI is a new CLI agent that can help you with your software development tasks and terminal operations.
22
+
23
+ See the following [instructions](https://github.com/MoonshotAI/kimi-cli?tab=readme-ov-file#usage) for how to configure Kimi before running.
24
+
25
+ '''
26
+
27
+
28
+ [actions."*".install]
29
+ command = "uv tool install kimi-cli --no-cache"
30
+ description = "Install Kimi CLI"
31
+
32
+
33
+ [actions."*".upgrade]
34
+ command = "uv tool upgrade kimi-cli --no-cache"
35
+ description = "Upgrade Kimi CLI"
@@ -0,0 +1,53 @@
1
+ # Schema defined in agent_schema.py
2
+ # https://github.com/openai/codex
3
+
4
+ identity = "openai.com"
5
+ name = "Codex CLI"
6
+ short_name = "codex"
7
+ url = "https://developers.openai.com/codex/cli/"
8
+ protocol = "acp"
9
+ author_name = "OpenAI"
10
+ author_url = "https://www.openai.com/"
11
+ publisher_name = "Will McGugan"
12
+ publisher_url = "https://willmcgugan.github.io/"
13
+ type = "coding"
14
+ description = "Lightweight coding agent by OpenAI that runs in your terminal with native ACP support."
15
+ tags = []
16
+ run_command."*" = "npx @zed-industries/codex-acp"
17
+
18
+ help = '''
19
+ # Codex CLI
20
+
21
+ **Lightweight coding agent that runs in your terminal**
22
+
23
+ Codex CLI is OpenAI's terminal-based coding agent with built-in support for the Agent Client Protocol.
24
+
25
+ ## Features
26
+
27
+ - **Agent Client Protocol (ACP)**: Native ACP support for seamless editor integration
28
+ - **Zed Integration**: Built-in support in Zed IDE (v0.208+)
29
+ - **Terminal-First**: Designed for developers who live in the command line
30
+
31
+ ## ACP Integration
32
+
33
+ Codex works out-of-the-box with ACP-compatible editors:
34
+ - Zed: Open agent panel (cmd-?/ctrl-?) and start a new Codex thread
35
+ - Other ACP clients: Use the `codex-acp` command
36
+
37
+ ## Installation
38
+
39
+ Install globally via npm or Homebrew:
40
+ - npm: `npm i -g @openai/codex`
41
+ - Homebrew: `brew install --cask codex`
42
+
43
+ For ACP adapter (used by editors): Install from https://github.com/zed-industries/codex-acp/releases
44
+
45
+ ---
46
+
47
+ **GitHub**: https://github.com/openai/codex
48
+ **ACP Adapter**: https://github.com/zed-industries/codex-acp
49
+ '''
50
+
51
+ [actions."*".install]
52
+ command = "npm install -g @openai/codex"
53
+ description = "Install Codex CLI"
@@ -0,0 +1,61 @@
1
+ # Schema defined in agent_schema.py
2
+ # https://github.com/sst/opencode
3
+
4
+ identity = "opencode.ai"
5
+ name = "OpenCode"
6
+ short_name = "opencode"
7
+ url = "https://opencode.ai/"
8
+ protocol = "acp"
9
+ author_name = "SST"
10
+ author_url = "https://sst.dev/"
11
+ publisher_name = "Will McGugan"
12
+ publisher_url = "https://willmcgugan.github.io/"
13
+ type = "coding"
14
+ description = "The AI coding agent built for the terminal with client/server architecture and ACP support via adapter."
15
+ tags = []
16
+ run_command."*" = "opencode acp"
17
+
18
+ help = '''
19
+ # OpenCode
20
+
21
+ **The AI coding agent built for the terminal**
22
+
23
+ OpenCode is an open source agent that helps you write and run code directly from the terminal with a flexible client/server architecture.
24
+
25
+ ## Key Features
26
+
27
+ - **Client/Server Architecture**: Run OpenCode on your computer while controlling it remotely
28
+ - **Terminal-Native**: Built for developers who work in the command line
29
+ - **Multi-LLM Support**: Works with various AI providers
30
+ - **GitHub Integration**: Deep integration with GitHub workflows
31
+
32
+ ## ACP Integration
33
+
34
+ OpenCode supports the Agent Client Protocol via the **opencode-acp** adapter by josephschmitt. This adapter:
35
+ - Launches a per-session MCP HTTP server
36
+ - Proxies file and terminal actions back to ACP
37
+ - Translates OpenCode streaming updates to ACP notifications
38
+ - Enables OpenCode to work with ACP-compatible editors
39
+
40
+ The ACP adapter allows standardized communication between OpenCode and various development tools.
41
+
42
+ ## Installation
43
+
44
+ Install OpenCode globally:
45
+ ```bash
46
+ npm install -g opencode
47
+ ```
48
+
49
+ For ACP support, install the adapter from:
50
+ https://github.com/josephschmitt/opencode-acp
51
+
52
+ ---
53
+
54
+ **Website**: https://opencode.ai/
55
+ **GitHub**: https://github.com/sst/opencode
56
+ **ACP Adapter**: https://github.com/josephschmitt/opencode-acp
57
+ '''
58
+
59
+ [actions."*".install]
60
+ command = "npm i -g opencode-ai"
61
+ description = "Install OpenCode"
@@ -0,0 +1,44 @@
1
+ # Schema defined in agent_schema.py
2
+ # https://www.claude.com/product/claude-code
3
+
4
+ identity = "openhands.dev"
5
+ name = "OpenHands"
6
+ short_name = "openhands"
7
+ url = "https://openhands.dev/"
8
+ protocol = "acp"
9
+ author_name = "OpenHands"
10
+ author_url = "https://openhands.dev/"
11
+ publisher_name = "Will McGugan"
12
+ publisher_url = "https://willmcgugan.github.io/"
13
+ type = "coding"
14
+ description = "The open platform for cloud coding agents. Scale from one to thousands of agents — open source, model-agnostic, and enterprise-ready. New users get [$text-success bold]$10[/] in free OpenHands Cloud credits!"
15
+ tags = []
16
+ run_command."*" = "openhands acp"
17
+ recommended = true
18
+
19
+ help = '''
20
+ # OpenHands
21
+
22
+ The open platform for cloud coding agents
23
+
24
+ Scale from one to thousands of agents -- open source, model agnostic, and enterprise-ready.
25
+
26
+ [openhands-dev](https://openhands.dev/)
27
+
28
+ ---
29
+
30
+ '''
31
+
32
+ welcome = '''
33
+ ## The future of software development must be written by engineers
34
+
35
+ Software development is changing. That change needs to happen in the open, driven by a community of professional developers. That's why OpenHands' software agent is MIT-licensed and trusted by a growing community.
36
+
37
+ Visit [openhands-dev](https://openhands.dev/) for more information.
38
+ '''
39
+
40
+ [actions."*".install]
41
+ command = "uv tool install openhands -U --python 3.12 && openhands login"
42
+ bootstrap_uv = true
43
+ description = "Install OpenHands"
44
+
@@ -0,0 +1,61 @@
1
+ # Schema defined in agent_schema.py
2
+ # https://github.com/stakpak/agent
3
+
4
+ identity = "stakpak.dev"
5
+ name = "Stakpak Agent"
6
+ short_name = "stakpak"
7
+ url = "https://stakpak.dev/"
8
+ protocol = "acp"
9
+ author_name = "Stakpak"
10
+ author_url = "https://stakpak.dev/"
11
+ publisher_name = "Will McGugan"
12
+ publisher_url = "https://willmcgugan.github.io/"
13
+ type = "coding"
14
+ description = "Terminal-native DevOps Agent in Rust with enterprise-grade security, ACP support, and IaC generation capabilities."
15
+ tags = []
16
+ run_command."*" = "stakpak acp"
17
+
18
+ help = '''
19
+ # Stakpak Agent
20
+
21
+ **The most secure agent built for operations & DevOps**
22
+
23
+ Stakpak is a terminal-native DevOps Agent built in Rust with enterprise-grade security features and Agent Client Protocol support.
24
+
25
+ ## Key Features
26
+
27
+ - **Enterprise-Grade Security**:
28
+ - Mutual TLS (mTLS) encryption
29
+ - Dynamic secret redaction
30
+ - Privacy-first architecture
31
+ - **DevOps Capabilities**: Run commands, edit files, search docs, and generate high-quality IaC
32
+ - **Agent Client Protocol (ACP)**: Native support for editor integration
33
+ - **Rust Performance**: Built in Rust for speed and reliability
34
+
35
+ ## ACP Integration
36
+
37
+ Stakpak implements the Agent Client Protocol, enabling integration with ACP-compatible editors and development environments like Zed, Neovim, and others.
38
+
39
+ ## Security
40
+
41
+ Stakpak emphasizes security with:
42
+ - End-to-end encryption via mTLS
43
+ - Automatic detection and redaction of sensitive information
44
+ - Privacy-first design principles
45
+
46
+ ## Use Cases
47
+
48
+ - Infrastructure as Code (IaC) generation
49
+ - DevOps automation
50
+ - Secure operations in production environments
51
+ - Terminal-based development workflows
52
+
53
+ ---
54
+
55
+ **GitHub**: https://github.com/stakpak/agent
56
+ **Website**: https://stakpak.dev/
57
+ '''
58
+
59
+ [actions."*".install]
60
+ command = "cargo install stakpak"
61
+ description = "Install Stakpak Agent via Cargo"
@@ -0,0 +1,27 @@
1
+ # Schema defined in agent_schema.py
2
+ # https://www.claude.com/product/claude-code
3
+
4
+ identity = "vibe.mistral.ai"
5
+ name = "Mistral Vibe"
6
+ short_name = "vibe"
7
+ url = "https://mistral.ai/news/devstral-2-vibe-cli"
8
+ protocol = "acp"
9
+ author_name = "Mistral"
10
+ author_url = "https://mistral.ai/"
11
+ publisher_name = "Will McGugan"
12
+ publisher_url = "https://willmcgugan.github.io/"
13
+ type = "coding"
14
+ description = "State-of-the-art, open-source agentic coding models and CLI agent."
15
+ tags = []
16
+ run_command."*" = "vibe-acp"
17
+
18
+ help = '''
19
+ # Devstral2 Mistral Vibe CLI
20
+
21
+ Today, we're releasing Devstral 2—our next-generation coding model family available in two sizes: Devstral 2 (123B) and Devstral Small 2 (24B). Devstral 2 ships under a modified MIT license, while Devstral Small 2 uses Apache 2.0. Both are open-source and permissively licensed to accelerate distributed intelligence.
22
+ '''
23
+
24
+
25
+ [actions."*".install]
26
+ command = "curl -LsSf https://mistral.ai/vibe/install.sh | bash"
27
+ description = "Install Mistral Vibe"
@@ -0,0 +1,62 @@
1
+ # Schema defined in agent_schema.py
2
+ # https://github.com/vinhnx/vtcode
3
+
4
+ identity = "vtcode.dev"
5
+ name = "VT Code"
6
+ short_name = "vtcode"
7
+ url = "https://github.com/vinhnx/vtcode"
8
+ protocol = "acp"
9
+ author_name = "Vinh Nguyen"
10
+ author_url = "https://github.com/vinhnx"
11
+ publisher_name = "Will McGugan"
12
+ publisher_url = "https://willmcgugan.github.io/"
13
+ type = "coding"
14
+ description = "Rust-based terminal coding agent with semantic code intelligence via Tree-sitter, ast-grep, and native Zed IDE integration via ACP."
15
+ tags = []
16
+ run_command."*" = "vtcode acp"
17
+
18
+ help = '''
19
+ # VT Code
20
+
21
+ **Semantic Coding Agent**
22
+
23
+ VT Code is a Rust-based terminal coding agent with semantic code intelligence and native support for the Agent Client Protocol.
24
+
25
+ ## Key Features
26
+
27
+ - **Semantic Code Intelligence**:
28
+ - Tree-sitter integration for syntax-aware analysis
29
+ - ast-grep integration for semantic search
30
+ - Advanced token budget tracking
31
+ - **Multi-LLM Support**: Works with multiple LLM providers with automatic failover
32
+ - **Rich Terminal UI**: Real-time streaming in a beautiful TUI
33
+ - **Editor Integration**: Native support for Zed IDE via ACP
34
+ - **Security**: Defense-in-depth security model
35
+
36
+ ## Smart Tools
37
+
38
+ - Built-in code analysis and refactoring
39
+ - File operations with semantic understanding
40
+ - Terminal command execution
41
+ - Lifecycle hooks for custom shell commands
42
+
43
+ ## Agent Client Protocol (ACP)
44
+
45
+ VT Code integrates natively with Zed IDE and other ACP-compatible editors. The ACP standardizes communication between code editors and coding agents.
46
+
47
+ ## Context Management
48
+
49
+ Efficient context curation with:
50
+ - Semantic search capabilities
51
+ - Token budget tracking
52
+ - Smart context window management
53
+
54
+ ---
55
+
56
+ **GitHub**: https://github.com/vinhnx/vtcode
57
+ **Author**: Vinh Nguyen (@vinhnx)
58
+ '''
59
+
60
+ [actions."*".install]
61
+ command = "cargo install --git https://github.com/vinhnx/vtcode"
62
+ description = "Install VT Code via Cargo"
Binary file
Binary file
toad/db.py ADDED
@@ -0,0 +1,5 @@
1
+ import sqlite3
2
+
3
+
4
+ def connect(path: str) -> sqlite3.Connection:
5
+ return sqlite3.connect(path)
toad/dec.py ADDED
@@ -0,0 +1,332 @@
1
+ # ============================================================================
2
+ # DEC SPECIAL GRAPHICS (Final character: '0')
3
+ # Used for: Box drawing, line graphics
4
+ # ============================================================================
5
+
6
+ DEC_GRAPHICS = {
7
+ 0x60: "◆", # ` -> diamond
8
+ 0x61: "▒", # a -> checkerboard
9
+ 0x62: "␉", # b -> HT symbol
10
+ 0x63: "␌", # c -> FF symbol
11
+ 0x64: "␍", # d -> CR symbol
12
+ 0x65: "␊", # e -> LF symbol
13
+ 0x66: "°", # f -> degree symbol
14
+ 0x67: "±", # g -> plus/minus
15
+ 0x68: "␤", # h -> NL symbol
16
+ 0x69: "␋", # i -> VT symbol
17
+ 0x6A: "┘", # j -> lower right corner
18
+ 0x6B: "┐", # k -> upper right corner
19
+ 0x6C: "┌", # l -> upper left corner
20
+ 0x6D: "└", # m -> lower left corner
21
+ 0x6E: "┼", # n -> crossing lines
22
+ 0x6F: "⎺", # o -> scan line 1
23
+ 0x70: "⎻", # p -> scan line 3
24
+ 0x71: "─", # q -> horizontal line
25
+ 0x72: "⎼", # r -> scan line 7
26
+ 0x73: "⎽", # s -> scan line 9
27
+ 0x74: "├", # t -> left tee
28
+ 0x75: "┤", # u -> right tee
29
+ 0x76: "┴", # v -> bottom tee
30
+ 0x77: "┬", # w -> top tee
31
+ 0x78: "│", # x -> vertical bar
32
+ 0x79: "≤", # y -> less than or equal
33
+ 0x7A: "≥", # z -> greater than or equal
34
+ 0x7B: "π", # { -> pi
35
+ 0x7C: "≠", # | -> not equal
36
+ 0x7D: "£", # } -> UK pound sign
37
+ 0x7E: "·", # ~ -> centered dot
38
+ }
39
+
40
+ # ============================================================================
41
+ # US ASCII (Final character: 'B')
42
+ # Used for: Standard ASCII - default
43
+ # No mapping needed - just use chr(code) directly
44
+ # ============================================================================
45
+
46
+ US_ASCII = {} # Identity mapping - no changes
47
+
48
+ # ============================================================================
49
+ # UK ASCII (Final character: 'A')
50
+ # Used for: British keyboard - pound sign
51
+ # ============================================================================
52
+
53
+ UK_ASCII = {
54
+ 0x23: "£", # # -> £ (pound sign)
55
+ }
56
+
57
+ # ============================================================================
58
+ # DEC SUPPLEMENTAL GRAPHICS (Final character: '<')
59
+ # Used for: Western European accented characters (GR range 0xA0-0xFF)
60
+ # These would normally go in GR, not GL
61
+ # ============================================================================
62
+
63
+ DEC_SUPPLEMENTAL = {
64
+ # Note: These are for the GR range (0xA0-0xFF), shown here with
65
+ # their effective codes after subtracting 0x80 (so 0x20-0x7F range)
66
+ 0x21: "¡", # A1 -> inverted exclamation
67
+ 0x22: "¢", # A2 -> cent sign
68
+ 0x23: "£", # A3 -> pound sign
69
+ 0x24: "¤", # A4 -> currency sign (was blank in doc)
70
+ 0x25: "¥", # A5 -> yen sign
71
+ 0x27: "§", # A7 -> section sign
72
+ 0x28: "¤", # A8 -> currency sign
73
+ 0x29: "©", # A9 -> copyright
74
+ 0x2A: "ª", # AA -> feminine ordinal
75
+ 0x2B: "«", # AB -> left guillemet
76
+ 0x30: "°", # B0 -> degree
77
+ 0x31: "±", # B1 -> plus-minus
78
+ 0x32: "²", # B2 -> superscript 2
79
+ 0x33: "³", # B3 -> superscript 3
80
+ 0x35: "µ", # B5 -> micro
81
+ 0x36: "¶", # B6 -> pilcrow (paragraph)
82
+ 0x37: "·", # B7 -> middle dot
83
+ 0x39: "¹", # B9 -> superscript 1
84
+ 0x3A: "º", # BA -> masculine ordinal
85
+ 0x3B: "»", # BB -> right guillemet
86
+ 0x3C: "¼", # BC -> one quarter
87
+ 0x3D: "½", # BD -> one half
88
+ 0x3F: "¿", # BF -> inverted question mark
89
+ 0x40: "À", # C0 -> A grave
90
+ 0x41: "Á", # C1 -> A acute
91
+ 0x42: "Â", # C2 -> A circumflex
92
+ 0x43: "Ã", # C3 -> A tilde
93
+ 0x44: "Ä", # C4 -> A diaeresis
94
+ 0x45: "Å", # C5 -> A ring
95
+ 0x46: "Æ", # C6 -> AE ligature
96
+ 0x47: "Ç", # C7 -> C cedilla
97
+ 0x48: "È", # C8 -> E grave
98
+ 0x49: "É", # C9 -> E acute
99
+ 0x4A: "Ê", # CA -> E circumflex
100
+ 0x4B: "Ë", # CB -> E diaeresis
101
+ 0x4C: "Ì", # CC -> I grave
102
+ 0x4D: "Í", # CD -> I acute
103
+ 0x4E: "Î", # CE -> I circumflex
104
+ 0x4F: "Ï", # CF -> I diaeresis
105
+ 0x51: "Ñ", # D1 -> N tilde
106
+ 0x52: "Ò", # D2 -> O grave
107
+ 0x53: "Ó", # D3 -> O acute
108
+ 0x54: "Ô", # D4 -> O circumflex
109
+ 0x55: "Õ", # D5 -> O tilde
110
+ 0x56: "Ö", # D6 -> O diaeresis
111
+ 0x57: "Œ", # D7 -> OE ligature
112
+ 0x58: "Ø", # D8 -> O slash
113
+ 0x59: "Ù", # D9 -> U grave
114
+ 0x5A: "Ú", # DA -> U acute
115
+ 0x5B: "Û", # DB -> U circumflex
116
+ 0x5C: "Ü", # DC -> U diaeresis
117
+ 0x5D: "Ÿ", # DD -> Y diaeresis
118
+ 0x5F: "ß", # DF -> sharp s (German)
119
+ 0x60: "à", # E0 -> a grave
120
+ 0x61: "á", # E1 -> a acute
121
+ 0x62: "â", # E2 -> a circumflex
122
+ 0x63: "ã", # E3 -> a tilde
123
+ 0x64: "ä", # E4 -> a diaeresis
124
+ 0x65: "å", # E5 -> a ring
125
+ 0x66: "æ", # E6 -> ae ligature
126
+ 0x67: "ç", # E7 -> c cedilla
127
+ 0x68: "è", # E8 -> e grave
128
+ 0x69: "é", # E9 -> e acute
129
+ 0x6A: "ê", # EA -> e circumflex
130
+ 0x6B: "ë", # EB -> e diaeresis
131
+ 0x6C: "ì", # EC -> i grave
132
+ 0x6D: "í", # ED -> i acute
133
+ 0x6E: "î", # EE -> i circumflex
134
+ 0x6F: "ï", # EF -> i diaeresis
135
+ 0x71: "ñ", # F1 -> n tilde
136
+ 0x72: "ò", # F2 -> o grave
137
+ 0x73: "ó", # F3 -> o acute
138
+ 0x74: "ô", # F4 -> o circumflex
139
+ 0x75: "õ", # F5 -> o tilde
140
+ 0x76: "ö", # F6 -> o diaeresis
141
+ 0x77: "œ", # F7 -> oe ligature
142
+ 0x78: "ø", # F8 -> o slash
143
+ 0x79: "ù", # F9 -> u grave
144
+ 0x7A: "ú", # FA -> u acute
145
+ 0x7B: "û", # FB -> u circumflex
146
+ 0x7C: "ü", # FC -> u diaeresis
147
+ 0x7D: "ÿ", # FD -> y diaeresis
148
+ }
149
+
150
+ # ============================================================================
151
+ # NATIONAL REPLACEMENT CHARACTER SETS
152
+ # These replace specific ASCII positions with national characters
153
+ # ============================================================================
154
+
155
+ # Dutch NRC (Final character: '4')
156
+ DUTCH_NRC = {
157
+ 0x23: "£", # # -> £
158
+ 0x40: "¾", # @ -> ¾
159
+ 0x5B: "ij", # [ -> ij ligature
160
+ 0x5C: "½", # \ -> ½
161
+ 0x5D: "|", # ] -> |
162
+ 0x7B: "¨", # { -> diaeresis
163
+ 0x7C: "f", # | -> f (florin)
164
+ 0x7D: "¼", # } -> ¼
165
+ 0x7E: "´", # ~ -> acute accent
166
+ }
167
+
168
+ # Finnish NRC (Final character: 'C' or '5')
169
+ FINNISH_NRC = {
170
+ 0x5B: "Ä", # [ -> Ä
171
+ 0x5C: "Ö", # \ -> Ö
172
+ 0x5D: "Å", # ] -> Å
173
+ 0x5E: "Ü", # ^ -> Ü
174
+ 0x60: "é", # ` -> é
175
+ 0x7B: "ä", # { -> ä
176
+ 0x7C: "ö", # | -> ö
177
+ 0x7D: "å", # } -> å
178
+ 0x7E: "ü", # ~ -> ü
179
+ }
180
+
181
+ # French NRC (Final character: 'R')
182
+ FRENCH_NRC = {
183
+ 0x23: "£", # # -> £
184
+ 0x40: "à", # @ -> à
185
+ 0x5B: "°", # [ -> °
186
+ 0x5C: "ç", # \ -> ç
187
+ 0x5D: "§", # ] -> §
188
+ 0x7B: "é", # { -> é
189
+ 0x7C: "ù", # | -> ù
190
+ 0x7D: "è", # } -> è
191
+ 0x7E: "¨", # ~ -> ¨
192
+ }
193
+
194
+ # French Canadian NRC (Final character: 'Q')
195
+ FRENCH_CANADIAN_NRC = {
196
+ 0x40: "à", # @ -> à
197
+ 0x5B: "â", # [ -> â
198
+ 0x5C: "ç", # \ -> ç
199
+ 0x5D: "ê", # ] -> ê
200
+ 0x5E: "î", # ^ -> î
201
+ 0x60: "ô", # ` -> ô
202
+ 0x7B: "é", # { -> é
203
+ 0x7C: "ù", # | -> ù
204
+ 0x7D: "è", # } -> è
205
+ 0x7E: "û", # ~ -> û
206
+ }
207
+
208
+ # German NRC (Final character: 'K')
209
+ GERMAN_NRC = {
210
+ 0x40: "§", # @ -> §
211
+ 0x5B: "Ä", # [ -> Ä
212
+ 0x5C: "Ö", # \ -> Ö
213
+ 0x5D: "Ü", # ] -> Ü
214
+ 0x7B: "ä", # { -> ä
215
+ 0x7C: "ö", # | -> ö
216
+ 0x7D: "ü", # } -> ü
217
+ 0x7E: "ß", # ~ -> ß
218
+ }
219
+
220
+ # Italian NRC (Final character: 'Y')
221
+ ITALIAN_NRC = {
222
+ 0x23: "£", # # -> £
223
+ 0x40: "§", # @ -> §
224
+ 0x5B: "°", # [ -> °
225
+ 0x5C: "ç", # \ -> ç
226
+ 0x5D: "é", # ] -> é
227
+ 0x60: "ù", # ` -> ù
228
+ 0x7B: "à", # { -> à
229
+ 0x7C: "ò", # | -> ò
230
+ 0x7D: "è", # } -> è
231
+ 0x7E: "ì", # ~ -> ì
232
+ }
233
+
234
+ # Norwegian/Danish NRC (Final character: 'E' or '6')
235
+ NORWEGIAN_DANISH_NRC = {
236
+ 0x40: "Ä", # @ -> Ä
237
+ 0x5B: "Æ", # [ -> Æ
238
+ 0x5C: "Ø", # \ -> Ø
239
+ 0x5D: "Å", # ] -> Å
240
+ 0x5E: "Ü", # ^ -> Ü
241
+ 0x60: "ä", # ` -> ä
242
+ 0x7B: "æ", # { -> æ
243
+ 0x7C: "ø", # | -> ø
244
+ 0x7D: "å", # } -> å
245
+ 0x7E: "ü", # ~ -> ü
246
+ }
247
+
248
+ # Spanish NRC (Final character: 'Z')
249
+ SPANISH_NRC = {
250
+ 0x23: "£", # # -> £
251
+ 0x40: "§", # @ -> §
252
+ 0x5B: "¡", # [ -> ¡
253
+ 0x5C: "Ñ", # \ -> Ñ
254
+ 0x5D: "¿", # ] -> ¿
255
+ 0x7B: "°", # { -> °
256
+ 0x7C: "ñ", # | -> ñ
257
+ 0x7D: "ç", # } -> ç
258
+ }
259
+
260
+ # Swedish NRC (Final character: 'H' or '7')
261
+ SWEDISH_NRC = {
262
+ 0x40: "É", # @ -> É
263
+ 0x5B: "Ä", # [ -> Ä
264
+ 0x5C: "Ö", # \ -> Ö
265
+ 0x5D: "Å", # ] -> Å
266
+ 0x5E: "Ü", # ^ -> Ü
267
+ 0x60: "é", # ` -> é
268
+ 0x7B: "ä", # { -> ä
269
+ 0x7C: "ö", # | -> ö
270
+ 0x7D: "å", # } -> å
271
+ 0x7E: "ü", # ~ -> ü
272
+ }
273
+
274
+ # Swiss NRC (Final character: '=')
275
+ SWISS_NRC = {
276
+ 0x23: "ù", # # -> ù
277
+ 0x40: "à", # @ -> à
278
+ 0x5B: "é", # [ -> é
279
+ 0x5C: "ç", # \ -> ç
280
+ 0x5D: "ê", # ] -> ê
281
+ 0x5E: "î", # ^ -> î
282
+ 0x5F: "è", # _ -> è
283
+ 0x60: "ô", # ` -> ô
284
+ 0x7B: "ä", # { -> ä
285
+ 0x7C: "ö", # | -> ö
286
+ 0x7D: "ü", # } -> ü
287
+ 0x7E: "û", # ~ -> û
288
+ }
289
+
290
+ # ============================================================================
291
+ # MASTER LOOKUP TABLE
292
+ # ============================================================================
293
+
294
+ CHARSET_MAP: dict[str, dict[int, str]] = {
295
+ "B": US_ASCII,
296
+ "A": UK_ASCII,
297
+ "0": DEC_GRAPHICS,
298
+ "<": DEC_SUPPLEMENTAL,
299
+ "4": DUTCH_NRC,
300
+ "5": FINNISH_NRC,
301
+ "C": FINNISH_NRC,
302
+ "R": FRENCH_NRC,
303
+ "Q": FRENCH_CANADIAN_NRC,
304
+ "K": GERMAN_NRC,
305
+ "Y": ITALIAN_NRC,
306
+ "E": NORWEGIAN_DANISH_NRC,
307
+ "6": NORWEGIAN_DANISH_NRC,
308
+ "Z": SPANISH_NRC,
309
+ "H": SWEDISH_NRC,
310
+ "7": SWEDISH_NRC,
311
+ "=": SWISS_NRC,
312
+ }
313
+
314
+ CHARSET_NAMES = {
315
+ "B": "US ASCII",
316
+ "A": "UK ASCII",
317
+ "0": "DEC Special Graphics",
318
+ "<": "DEC Supplemental Graphics",
319
+ "4": "Dutch NRC",
320
+ "5": "Finnish NRC",
321
+ "C": "Finnish NRC",
322
+ "R": "French NRC",
323
+ "Q": "French Canadian NRC",
324
+ "K": "German NRC",
325
+ "Y": "Italian NRC",
326
+ "E": "Norwegian/Danish NRC",
327
+ "6": "Norwegian/Danish NRC",
328
+ "Z": "Spanish NRC",
329
+ "H": "Swedish NRC",
330
+ "7": "Swedish NRC",
331
+ "=": "Swiss NRC",
332
+ }