refactor: restructure chat-vault to services architecture
This commit is contained in:
parent
1414b45a1b
commit
318ae2b416
|
|
@ -1,28 +1,159 @@
|
|||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
*.egg-info/
|
||||
dist/
|
||||
*.jsonl
|
||||
.Python
|
||||
build/
|
||||
*.spec
|
||||
|
||||
# Output
|
||||
output/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
*.csv
|
||||
*.zip
|
||||
*.jsonl
|
||||
*.db
|
||||
*.sqlite3
|
||||
*.log
|
||||
*.pyc
|
||||
*.png
|
||||
libs/database/csv/futures/
|
||||
*.jpg
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.venv/
|
||||
# Virtual Environment
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
.venv_telegram/
|
||||
*.gz
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
.github/
|
||||
*.swp
|
||||
|
||||
# OS
|
||||
*.swo
|
||||
*~
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Testing
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
*.log.[0-9]*
|
||||
*.out
|
||||
logs/*.log
|
||||
logs/*.out
|
||||
|
||||
# 项目特定
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# Celery
|
||||
*.pyc
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# backtest folder
|
||||
src/backtest/
|
||||
|
||||
# Additional exclusions
|
||||
.history/
|
||||
.venv_patterns/
|
||||
logs/
|
||||
|
||||
# src/telegram venv
|
||||
src/telegram/venv
|
||||
services/data-service/src/backtest/
|
||||
|
||||
# Backup files
|
||||
*.bak
|
||||
*.tmp
|
||||
backups/gz/
|
||||
|
||||
# Data service exclusions
|
||||
services/data-service/data/csv/缺口补齐/
|
||||
services/data-service/data/csv/backups/
|
||||
services/data-service/data/csv/exports/
|
||||
services/data-service/data/csv/futures/
|
||||
|
||||
# OS-specific
|
||||
|
||||
# OS-specific
|
||||
|
||||
data/csv/缺口补齐
|
||||
data/csv/backups
|
||||
data/csv/exports
|
||||
data/csv/futures
|
||||
# Custom rule for metrics data
|
||||
services/data-service/data/csv/metrics/
|
||||
|
||||
# Rust build artifacts (order-service)
|
||||
services/order-service/target/
|
||||
services/order-service/services/backend-service/target/
|
||||
|
||||
# Frontend service node_modules
|
||||
services/order-service/services/frontend-service/node_modules/
|
||||
|
||||
# order-service external vendor mirrors
|
||||
services/order-service/libs/external/
|
||||
|
||||
# External vendor mirrors (mirror-only, never commit)
|
||||
# 默认忽略 external 下所有内容,但保留少量文档
|
||||
libs/external/*
|
||||
!libs/external/AGENTS.md
|
||||
!libs/external/README.md
|
||||
!libs/external/CLAUDE.md
|
||||
# 常见镜像目录(冗余标记,便于阅读)
|
||||
libs/external/backtrader-master/
|
||||
libs/external/CodeWeaver-main/
|
||||
libs/external/crypto-trading-open-main/
|
||||
libs/external/cryptofeed-master/
|
||||
libs/external/flowsurface-main/
|
||||
libs/external/freqtrade-develop/
|
||||
libs/external/hftbacktest-master/
|
||||
libs/external/hummingbot-master/
|
||||
libs/external/lean-master/
|
||||
libs/external/lightweight-charts-master/
|
||||
libs/external/qlib-main/
|
||||
libs/external/qstrader-master/
|
||||
libs/external/vnpy-master/
|
||||
libs/external/zipline-main/
|
||||
backups/archive
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
# Git Submodules
|
||||
# 示例:
|
||||
# [submodule "libs/external/some-lib"]
|
||||
# path = libs/external/some-lib
|
||||
# url = https://github.com/xxx/some-lib.git
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
# AGENTS.md
|
||||
|
||||
AI Agent 操作手册 - Chat Vault Monorepo
|
||||
|
||||
---
|
||||
|
||||
## 1. Mission & Scope(目标与边界)
|
||||
|
||||
### 允许操作
|
||||
- 修改 `services/chat-vault/src/` 下的 Python 代码
|
||||
- 添加新的解析器到 `services/chat-vault/src/parsers/`
|
||||
- 更新文档 (`README.md`, `AGENTS.md`, `docs/`)
|
||||
- 修改配置示例 `.env.example`
|
||||
|
||||
### 禁止操作
|
||||
- **禁止修改** `output/` 目录下的任何文件(数据库、日志)
|
||||
- **禁止修改** `.env` 文件(包含用户敏感配置)
|
||||
- **禁止修改** `libs/external/` 下的外部依赖镜像
|
||||
- **禁止删除** 现有解析器,除非明确要求
|
||||
|
||||
### 敏感区域
|
||||
| 路径 | 说明 |
|
||||
|------|------|
|
||||
| `services/chat-vault/.env` | 用户配置,不得读取或修改 |
|
||||
| `services/chat-vault/output/` | 运行时数据,不得修改 |
|
||||
| `libs/external/` | 外部镜像,只读 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Golden Path(推荐执行路径)
|
||||
|
||||
```bash
|
||||
# 1. 进入服务目录
|
||||
cd services/chat-vault
|
||||
|
||||
# 2. 首次运行(自动创建 venv 并安装依赖)
|
||||
python src/main.py
|
||||
|
||||
# 3. 验证功能
|
||||
python src/main.py --stats
|
||||
|
||||
# 4. 修改代码后测试
|
||||
python src/main.py # 同步测试
|
||||
python src/main.py --search "test" # 搜索测试
|
||||
|
||||
# 5. 更新文档(如有变更)
|
||||
# 编辑 README.md, AGENTS.md, docs/schema.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Must-Run Commands(必须执行的命令)
|
||||
|
||||
### 环境准备
|
||||
```bash
|
||||
cd services/chat-vault
|
||||
python src/main.py # 首次运行自动安装依赖
|
||||
```
|
||||
|
||||
### 依赖文件
|
||||
- `services/chat-vault/requirements.txt`
|
||||
```
|
||||
python-dotenv>=1.0.0
|
||||
watchdog>=3.0.0
|
||||
tiktoken>=0.5.0
|
||||
```
|
||||
|
||||
### 功能验证
|
||||
```bash
|
||||
# 同步一次
|
||||
python src/main.py
|
||||
|
||||
# 查看统计
|
||||
python src/main.py --stats
|
||||
|
||||
# 监控模式
|
||||
python src/main.py --watch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Code Change Rules(修改约束)
|
||||
|
||||
### 架构原则
|
||||
- 解析器必须继承 `parsers/base.py` 的 `SessionData` 数据结构
|
||||
- 新增 CLI 支持需在 `parsers/__init__.py` 中导出
|
||||
- 配置项通过 `config.py` 的 `CONFIG` 字典访问
|
||||
|
||||
### 模块边界
|
||||
| 模块 | 职责 | 禁止 |
|
||||
|------|------|------|
|
||||
| `main.py` | CLI 入口、命令分发 | 不含业务逻辑 |
|
||||
| `config.py` | 路径检测、配置加载 | 不含 I/O 操作 |
|
||||
| `storage.py` | SQLite 读写、Token 计数 | 不含解析逻辑 |
|
||||
| `watcher.py` | 文件监控 | 不含存储逻辑 |
|
||||
| `parsers/*.py` | 各 CLI 格式解析 | 不含存储逻辑 |
|
||||
|
||||
### 依赖添加规则
|
||||
- 新依赖必须添加到 `requirements.txt`
|
||||
- 优先使用标准库
|
||||
- 避免引入大型框架
|
||||
|
||||
### 兼容性要求
|
||||
- Python 3.8+ 兼容
|
||||
- 跨平台:Linux / macOS / Windows (WSL)
|
||||
- WSL 路径格式:`\\wsl.localhost\Ubuntu\...`
|
||||
|
||||
---
|
||||
|
||||
## 5. Style & Quality(风格与质量)
|
||||
|
||||
### 代码风格
|
||||
- 文件头:`#!/usr/bin/env python3` + `# -*- coding: utf-8 -*-`
|
||||
- 缩进:4 空格
|
||||
- 行宽:建议 100 字符
|
||||
- 命名:snake_case(函数/变量),PascalCase(类)
|
||||
|
||||
### 文档要求
|
||||
- 每个模块需有 docstring 说明用途
|
||||
- 公开函数需有参数/返回值说明
|
||||
- 复杂逻辑需有行内注释
|
||||
|
||||
### 错误处理
|
||||
- 解析失败记录到日志,不中断流程
|
||||
- 使用 `logger.py` 的 `get_logger()` 记录
|
||||
|
||||
---
|
||||
|
||||
## 6. Project Map(项目结构速览)
|
||||
|
||||
```
|
||||
chat-vault/
|
||||
├── services/chat-vault/ # 核心服务
|
||||
│ ├── src/
|
||||
│ │ ├── main.py # 入口:CLI 命令分发
|
||||
│ │ ├── config.py # 配置:路径检测、环境变量
|
||||
│ │ ├── storage.py # 存储:SQLite + tiktoken
|
||||
│ │ ├── watcher.py # 监控:watchdog 封装
|
||||
│ │ ├── logger.py # 日志:统一日志配置
|
||||
│ │ └── parsers/
|
||||
│ │ ├── __init__.py # 导出所有解析器
|
||||
│ │ ├── base.py # SessionData 数据结构
|
||||
│ │ ├── codex.py # Codex CLI 解析
|
||||
│ │ ├── kiro.py # Kiro CLI 解析
|
||||
│ │ ├── gemini.py # Gemini CLI 解析
|
||||
│ │ └── claude.py # Claude CLI 解析
|
||||
│ ├── docs/
|
||||
│ │ ├── schema.md # 数据库结构文档
|
||||
│ │ ├── roadmap.md # 开发路线图
|
||||
│ │ └── AI_PROMPT.md # AI 助手指南
|
||||
│ ├── requirements.txt # Python 依赖
|
||||
│ ├── .env.example # 配置示例
|
||||
│ ├── start.sh # Linux/macOS 启动脚本
|
||||
│ └── start.bat # Windows 启动脚本
|
||||
├── libs/ # 共享库(预留)
|
||||
├── monitoring/ # 监控配置(预留)
|
||||
├── scripts/ # 全局脚本
|
||||
├── README.md # 项目说明
|
||||
└── AGENTS.md # 本文件
|
||||
```
|
||||
|
||||
### 关键入口
|
||||
- **CLI 入口**: `services/chat-vault/src/main.py`
|
||||
- **配置加载**: `services/chat-vault/src/config.py` → `CONFIG` 字典
|
||||
- **数据库**: `services/chat-vault/output/chat_history.db`
|
||||
|
||||
---
|
||||
|
||||
## 7. Common Pitfalls(常见问题)
|
||||
|
||||
| 问题 | 原因 | 解决 |
|
||||
|------|------|------|
|
||||
| `ModuleNotFoundError` | 未在 venv 中运行 | 运行 `python src/main.py` 自动创建 venv |
|
||||
| 路径未检测到 | 默认路径不存在 | 在 `.env` 中配置 `CODEX_PATHS` 等 |
|
||||
| WSL 路径失败 | 格式错误 | 使用 `\\wsl.localhost\Ubuntu\...` 格式 |
|
||||
| Token 计数为 0 | tiktoken 未安装 | 检查 `requirements.txt` 是否包含 tiktoken |
|
||||
| 数据库锁定 | 多进程同时写入 | 确保只有一个实例运行 |
|
||||
|
||||
---
|
||||
|
||||
## 8. PR / Commit Rules(提交规则)
|
||||
|
||||
### Commit Message 格式
|
||||
```
|
||||
<type>(<scope>): <description>
|
||||
|
||||
type: feat|fix|docs|refactor|test|chore
|
||||
scope: chat-vault|parsers|storage|config|docs
|
||||
```
|
||||
|
||||
示例:
|
||||
```
|
||||
feat(parsers): add support for new CLI format
|
||||
fix(storage): handle empty message array
|
||||
docs(readme): update quick start section
|
||||
```
|
||||
|
||||
### 分支策略
|
||||
- `main`: 稳定版本
|
||||
- `dev`: 开发分支
|
||||
- `feature/*`: 功能分支
|
||||
|
||||
---
|
||||
|
||||
## 9. Documentation Sync Rule(文档同步规则)
|
||||
|
||||
### 强制同步
|
||||
以下变更必须同步更新文档:
|
||||
|
||||
| 变更类型 | 需更新文档 |
|
||||
|----------|-----------|
|
||||
| 新增命令行参数 | README.md, AGENTS.md |
|
||||
| 新增解析器 | README.md (功能特性), AGENTS.md (Project Map) |
|
||||
| 数据库结构变更 | docs/schema.md |
|
||||
| 配置项变更 | README.md (配置说明), .env.example |
|
||||
| 目录结构变更 | README.md, AGENTS.md |
|
||||
|
||||
### 不确定时
|
||||
- 使用 `TODO: 需确认 <具体问题>` 标注
|
||||
- 不允许猜测或编造
|
||||
|
||||
---
|
||||
|
||||
## 10. Quick Reference(速查)
|
||||
|
||||
```bash
|
||||
# 同步
|
||||
python src/main.py
|
||||
|
||||
# 监控
|
||||
python src/main.py --watch
|
||||
|
||||
# 统计
|
||||
python src/main.py --stats
|
||||
|
||||
# 搜索
|
||||
python src/main.py --search "关键词"
|
||||
|
||||
# 导出
|
||||
python src/main.py --export json
|
||||
python src/main.py --export csv --source codex
|
||||
|
||||
# 清理
|
||||
python src/main.py --prune
|
||||
```
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# CLAUDE.md
|
||||
|
||||
Claude 持久上下文文件
|
||||
|
||||
## 项目概述
|
||||
这是一个 monorepo 项目,包含多个微服务。
|
||||
|
||||
## 目录结构
|
||||
- services/ - 微服务
|
||||
- libs/ - 共享库
|
||||
- infrastructure/ - 基础设施配置
|
||||
- monitoring/ - 监控系统
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024
|
||||
Copyright (c) 2025
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,318 +1,143 @@
|
|||
<div align="center">
|
||||
# Chat Vault Monorepo
|
||||
|
||||
# 🔐 Chat Vault
|
||||
AI 聊天记录集中存储与管理平台。
|
||||
|
||||
**One tool to save ALL your AI chat history**
|
||||
## 项目概述
|
||||
|
||||
[](https://python.org)
|
||||
[](LICENSE)
|
||||
[]()
|
||||
[]()
|
||||
本项目是一个 monorepo,包含 AI 聊天记录同步工具及相关基础设施。核心功能是将多个 AI CLI 工具(Codex、Kiro、Gemini、Claude)的聊天记录统一存储到 SQLite 数据库。
|
||||
|
||||
[English](README.md) | [中文](README_CN.md)
|
||||
## 功能特性
|
||||
|
||||
[✨ Features](#-features) •
|
||||
[🚀 Quick Start](#-quick-start) •
|
||||
[📋 Commands](#-commands) •
|
||||
[📁 Project Structure](#-project-structure) •
|
||||
[❓ FAQ](#-faq)
|
||||
- 多 CLI 支持:Codex、Kiro、Gemini、Claude
|
||||
- 实时监控:基于 watchdog 的文件变更检测
|
||||
- Token 统计:使用 tiktoken (cl100k_base) 精确计数
|
||||
- 搜索导出:支持关键词搜索、JSON/CSV 导出
|
||||
- 零配置:自动检测默认路径,开箱即用
|
||||
|
||||
[📞 Contact](#-contact) •
|
||||
[✨ Support](#-support) •
|
||||
[🤝 Contributing](#-contributing)
|
||||
## 快速开始
|
||||
|
||||
AI-powered docs: [zread.ai/tukuaiai/chat-vault](https://zread.ai/tukuaiai/chat-vault)
|
||||
### 环境要求
|
||||
|
||||
> 📦 This tool is part of [vibe-coding-cn](https://github.com/tukuaiai/vibe-coding-cn) - A comprehensive Vibe Coding guide
|
||||
- Python 3.8+
|
||||
- Linux / macOS / Windows (WSL)
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>🔄 <b>Multi-CLI</b></td>
|
||||
<td>Codex, Kiro, Gemini, Claude - all supported</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>⚡ <b>Real-time</b></td>
|
||||
<td>Watch mode with system-level file monitoring</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🔢 <b>Token Stats</b></td>
|
||||
<td>Accurate counting using tiktoken (cl100k_base)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🔍 <b>Search</b></td>
|
||||
<td>Find any conversation instantly</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>📤 <b>Export</b></td>
|
||||
<td>JSON or CSV, your choice</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🚀 <b>Zero Config</b></td>
|
||||
<td>Auto-detects paths, just run it</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph Sources
|
||||
A[~/.codex]
|
||||
B[~/.kiro]
|
||||
C[~/.gemini]
|
||||
D[~/.claude]
|
||||
end
|
||||
|
||||
subgraph Chat Vault
|
||||
E[Watcher]
|
||||
F[Parsers]
|
||||
G[Storage]
|
||||
end
|
||||
|
||||
subgraph Output
|
||||
H[(SQLite DB)]
|
||||
end
|
||||
|
||||
A --> E
|
||||
B --> E
|
||||
C --> E
|
||||
D --> E
|
||||
E --> F
|
||||
F --> G
|
||||
G --> H
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 How It Works
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant CLI as AI CLI (Codex/Kiro/...)
|
||||
participant Watcher
|
||||
participant Parser
|
||||
participant DB as SQLite
|
||||
|
||||
User->>CLI: Chat with AI
|
||||
CLI->>CLI: Save to local file
|
||||
Watcher->>Watcher: Detect file change
|
||||
Watcher->>Parser: Parse new content
|
||||
Parser->>DB: Upsert session
|
||||
DB-->>User: Query anytime
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 30 Seconds Setup
|
||||
### 启动服务
|
||||
|
||||
```bash
|
||||
# Clone
|
||||
git clone https://github.com/tukuaiai/vibe-coding-cn.git
|
||||
cd vibe-coding-cn/libs/external/chat-vault
|
||||
cd services/chat-vault
|
||||
|
||||
# Run (auto-installs dependencies)
|
||||
./start.sh # Linux/macOS
|
||||
start.bat # Windows
|
||||
# Linux/macOS
|
||||
./start.sh
|
||||
|
||||
# Windows
|
||||
start.bat
|
||||
```
|
||||
|
||||
**That's it!** 🎉
|
||||
首次运行会自动创建虚拟环境并安装依赖。
|
||||
|
||||
---
|
||||
|
||||
## 📊 Example Output
|
||||
|
||||
```
|
||||
==================================================
|
||||
AI 聊天记录 → 集中存储
|
||||
==================================================
|
||||
数据库: ./output/chat_history.db
|
||||
|
||||
[Codex] 新增:1241 更新:0 跳过:0 错误:0
|
||||
[Kiro] 新增:21 更新:0 跳过:0 错误:0
|
||||
[Gemini] 新增:332 更新:0 跳过:0 错误:0
|
||||
[Claude] 新增:168 更新:0 跳过:0 错误:0
|
||||
|
||||
==================================================
|
||||
总计: 1762 会话, 40000+ 消息
|
||||
✓ 同步完成!
|
||||
|
||||
=== Token 统计 (tiktoken) ===
|
||||
codex: 11,659,952 tokens
|
||||
kiro: 26,337 tokens
|
||||
gemini: 3,195,821 tokens
|
||||
claude: 29,725 tokens
|
||||
总计: 14,911,835 tokens
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `python src/main.py` | Sync once |
|
||||
| `python src/main.py -w` | Watch mode (real-time) |
|
||||
| `python src/main.py --stats` | Show statistics |
|
||||
| `python src/main.py --search "keyword"` | Search messages |
|
||||
| `python src/main.py --export json` | Export to JSON |
|
||||
| `python src/main.py --export csv --source codex` | Export specific source |
|
||||
| `python src/main.py --prune` | Clean orphaned records |
|
||||
|
||||
---
|
||||
|
||||
## 📁 Project Structure
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
chat-vault/
|
||||
├── 🚀 start.sh / start.bat # One-click start
|
||||
├── 📦 build.py # Build standalone exe
|
||||
├── 📂 src/
|
||||
│ ├── main.py # CLI entry
|
||||
│ ├── config.py # Auto-detection
|
||||
│ ├── storage.py # SQLite + tiktoken
|
||||
│ ├── watcher.py # File monitoring
|
||||
│ └── parsers/ # CLI parsers
|
||||
├── 📂 docs/
|
||||
│ ├── AI_PROMPT.md # AI assistant guide
|
||||
│ └── schema.md # Database schema
|
||||
└── 📂 output/
|
||||
├── chat_history.db # Your database
|
||||
└── logs/ # Sync logs
|
||||
├── services/
|
||||
│ └── chat-vault/ # 核心同步服务
|
||||
│ ├── src/
|
||||
│ │ ├── main.py # CLI 入口
|
||||
│ │ ├── config.py # 配置与路径检测
|
||||
│ │ ├── storage.py # SQLite 存储
|
||||
│ │ ├── watcher.py # 文件监控
|
||||
│ │ └── parsers/ # 各 CLI 解析器
|
||||
│ ├── docs/ # 服务文档
|
||||
│ ├── scripts/ # 辅助脚本
|
||||
│ ├── requirements.txt
|
||||
│ ├── start.sh
|
||||
│ └── .env.example
|
||||
├── libs/
|
||||
│ ├── common/ # 共享库(预留)
|
||||
│ ├── database/ # 数据库工具(预留)
|
||||
│ └── external/ # 外部依赖镜像
|
||||
├── monitoring/
|
||||
│ ├── grafana/ # Grafana 配置
|
||||
│ ├── prometheus/ # Prometheus 配置(预留)
|
||||
│ └── alertmanager/ # 告警配置(预留)
|
||||
├── scripts/ # 全局脚本
|
||||
│ ├── build_all.sh
|
||||
│ ├── test_all.sh
|
||||
│ └── deploy.sh
|
||||
├── docs/ # 全局文档
|
||||
├── AGENTS.md
|
||||
├── README.md
|
||||
└── LICENSE
|
||||
```
|
||||
|
||||
---
|
||||
## 常用命令
|
||||
|
||||
## 🗄️ Database Schema
|
||||
在 `services/chat-vault/` 目录下执行:
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
sessions {
|
||||
TEXT file_path PK
|
||||
TEXT session_id
|
||||
TEXT source
|
||||
TEXT cwd
|
||||
TEXT messages
|
||||
INTEGER file_mtime
|
||||
TEXT start_time
|
||||
INTEGER token_count
|
||||
}
|
||||
|
||||
meta {
|
||||
TEXT key PK
|
||||
TEXT value
|
||||
}
|
||||
|
||||
meta_codex {
|
||||
TEXT key PK
|
||||
TEXT value
|
||||
}
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `python src/main.py` | 同步一次 |
|
||||
| `python src/main.py -w` | 持续监控模式 |
|
||||
| `python src/main.py --stats` | 显示统计信息 |
|
||||
| `python src/main.py --search "关键词"` | 搜索消息 |
|
||||
| `python src/main.py --export json` | 导出 JSON |
|
||||
| `python src/main.py --export csv --source codex` | 导出指定来源 |
|
||||
| `python src/main.py --prune` | 清理孤立记录 |
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 环境变量(可选)
|
||||
|
||||
参考 `services/chat-vault/.env.example`:
|
||||
|
||||
```bash
|
||||
# 自定义路径(逗号分隔多个)
|
||||
CODEX_PATHS=~/.codex/sessions
|
||||
KIRO_PATHS=~/.local/share/kiro-cli
|
||||
GEMINI_PATHS=~/.gemini/tmp
|
||||
CLAUDE_PATHS=~/.claude
|
||||
|
||||
# WSL 路径支持
|
||||
CODEX_PATHS=\\wsl.localhost\Ubuntu\home\user\.codex\sessions
|
||||
```
|
||||
|
||||
---
|
||||
默认自动检测以下路径:
|
||||
- Codex: `~/.codex/sessions`, `~/.codex`
|
||||
- Kiro: `~/.local/share/kiro-cli`
|
||||
- Gemini: `~/.gemini/tmp`, `~/.gemini`
|
||||
- Claude: `~/.claude`
|
||||
|
||||
## 🤖 For AI Assistants
|
||||
### 输出位置
|
||||
|
||||
Send [docs/AI_PROMPT.md](docs/AI_PROMPT.md) to your AI assistant for:
|
||||
- SQL query examples
|
||||
- Python code snippets
|
||||
- Task guidance
|
||||
- 数据库:`services/chat-vault/output/chat_history.db`
|
||||
- 日志:`services/chat-vault/output/logs/`
|
||||
|
||||
---
|
||||
## 数据库结构
|
||||
|
||||
## ❓ FAQ
|
||||
详见 `services/chat-vault/docs/schema.md`
|
||||
|
||||
<details>
|
||||
<summary><b>Do I need to configure anything?</b></summary>
|
||||
主表 `sessions`:
|
||||
- `file_path` (PK): 源文件路径
|
||||
- `session_id`: 会话 ID
|
||||
- `source`: 来源 (codex/kiro/gemini/claude)
|
||||
- `messages`: JSON 消息数组
|
||||
- `token_count`: Token 数量
|
||||
|
||||
No. Auto-detects `~/.codex`, `~/.kiro`, `~/.gemini`, `~/.claude`
|
||||
</details>
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
<summary><b>Does it work with WSL?</b></summary>
|
||||
**Q: 需要配置吗?**
|
||||
A: 不需要,自动检测默认路径。
|
||||
|
||||
Yes! Paths like `\\wsl.localhost\Ubuntu\...` are supported
|
||||
</details>
|
||||
**Q: 支持 WSL 吗?**
|
||||
A: 支持,`\\wsl.localhost\Ubuntu\...` 格式路径会自动转换。
|
||||
|
||||
<details>
|
||||
<summary><b>How do I view the database?</b></summary>
|
||||
**Q: 数据安全吗?**
|
||||
A: 只读取 AI 工具的文件,不修改原始数据。
|
||||
|
||||
Use [DB Browser for SQLite](https://sqlitebrowser.org/) or any SQLite tool
|
||||
</details>
|
||||
## 贡献
|
||||
|
||||
<details>
|
||||
<summary><b>Is my data safe?</b></summary>
|
||||
欢迎提交 Issue 和 Pull Request。
|
||||
|
||||
Yes. We only READ from AI tools, never modify original files
|
||||
</details>
|
||||
## 许可证
|
||||
|
||||
---
|
||||
|
||||
## 📞 Contact
|
||||
|
||||
- **GitHub**: [tukuaiai](https://github.com/tukuaiai)
|
||||
- **Twitter / X**: [123olp](https://x.com/123olp)
|
||||
- **Telegram**: [@desci0](https://t.me/desci0)
|
||||
- **Telegram Group**: [glue_coding](https://t.me/glue_coding)
|
||||
- **Telegram Channel**: [tradecat_ai_channel](https://t.me/tradecat_ai_channel)
|
||||
- **Email**: tukuai.ai@gmail.com
|
||||
|
||||
---
|
||||
|
||||
## ✨ Support
|
||||
|
||||
If this project helped you, consider supporting:
|
||||
|
||||
- **Binance UID**: `572155580`
|
||||
- **Tron (TRC20)**: `TQtBXCSTwLFHjBqTS4rNUp7ufiGx51BRey`
|
||||
- **Solana**: `HjYhozVf9AQmfv7yv79xSNs6uaEU5oUk2USasYQfUYau`
|
||||
- **Ethereum (ERC20)**: `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC`
|
||||
- **BNB Smart Chain (BEP20)**: `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC`
|
||||
- **Bitcoin**: `bc1plslluj3zq3snpnnczplu7ywf37h89dyudqua04pz4txwh8z5z5vsre7nlm`
|
||||
- **Sui**: `0xb720c98a48c77f2d49d375932b2867e793029e6337f1562522640e4f84203d2e`
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome all contributions! Feel free to open an [Issue](https://github.com/tukuaiai/vibe-coding-cn/issues) or submit a [Pull Request](https://github.com/tukuaiai/vibe-coding-cn/pulls).
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
[MIT](LICENSE) - Do whatever you want with it.
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**If this helped you, give it a ⭐!**
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://www.star-history.com/#tukuaiai/vibe-coding-cn&type=Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
**Made with ❤️ by [tukuaiai](https://github.com/tukuaiai)**
|
||||
|
||||
[⬆ Back to Top](#-chat-vault)
|
||||
|
||||
</div>
|
||||
MIT License
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
# Sublime-Text.txt
|
||||
# 需求和注意事项,给自己看的 ^_^
|
||||
|
||||
## 会话恢复指令
|
||||
# TODO: 添加CLI会话恢复指令
|
||||
|
||||
## 需求记录
|
||||
|
||||
## 注意事项
|
||||
|
|
@ -0,0 +1 @@
|
|||
# 架构文档
|
||||
|
|
@ -0,0 +1 @@
|
|||
# 部署文档
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[*.{cpp,h,hpp,sh,md,cfg,sample}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: aristocratos
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: aristocratos
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: https://paypal.me/aristocratos
|
||||
59
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
59
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
labels: bug
|
||||
|
||||
---
|
||||
|
||||
**Read the README.md and search for similar issues before posting a bug report!**
|
||||
|
||||
<!-- Any bug that can be solved by just reading the [prerequisites](https://github.com/aristocratos/btop#prerequisites) section of the README will likely be ignored. -->
|
||||
|
||||
**Describe the bug**
|
||||
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**To Reproduce**
|
||||
|
||||
<!-- Steps to reproduce the behavior. ->
|
||||
|
||||
**Expected behavior**
|
||||
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
**Screenshots**
|
||||
|
||||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
**Info (please complete the following information):**
|
||||
- btop++ version: `btop --version`
|
||||
- If using snap: `snap info btop`
|
||||
- Binary: [self compiled or static binary from release]
|
||||
- Architecture: [x86_64, aarch64, etc.] `uname -m`
|
||||
- Platform: [Linux, FreeBSD, OsX]
|
||||
- (Linux) Kernel: `uname -r`
|
||||
- (OSX/FreeBSD) Os release version:
|
||||
- Terminal used:
|
||||
- Font used:
|
||||
|
||||
**Additional context**
|
||||
|
||||
<!-- Contents of `~/.local/state/btop.log` -->
|
||||
|
||||
<!-- Note: The snap uses: `~/snap/btop/current/.local/state/btop.log` -->
|
||||
|
||||
<!-- (try running btop with `--debug` flag if btop.log is empty) -->
|
||||
|
||||
**GDB Backtrace**
|
||||
|
||||
<!-- If btop++ is crashing at start the following steps could be helpful: -->
|
||||
|
||||
<!-- (Extra helpful if compiled with `make OPTFLAGS="-O0 -g"`) -->
|
||||
|
||||
<!-- 1. run (linux): `gdb btop` (macos): `lldb btop` -->
|
||||
|
||||
<!-- 2. `r` to run, wait for crash and press enter if prompted, CTRL+L to clear screen if needed. -->
|
||||
|
||||
<!-- 3. (gdb): `thread apply all bt` (lldb): `bt all` to get backtrace for all threads -->
|
||||
|
||||
<!-- 4. Copy and paste the backtrace here: -->
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
labels: feature
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
|
||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
**Describe the solution you'd like**
|
||||
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
**Additional context**
|
||||
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
||||
48
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-freebsd.yml
vendored
Normal file
48
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-freebsd.yml
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
name: FreeBSD CMake
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
tags-ignore: '*.*'
|
||||
paths:
|
||||
- '.github/workflows/cmake-freebsd.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/freebsd/*pp'
|
||||
pull_request:
|
||||
branches: main
|
||||
paths:
|
||||
- '.github/workflows/cmake-freebsd.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/freebsd/*pp'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: freebsd-${{ matrix.version}}-${{ matrix.arch}}
|
||||
runs-on: ubuntu-24.04
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.arch }}-${{ matrix.version }}
|
||||
cancel-in-progress: true
|
||||
strategy:
|
||||
matrix:
|
||||
arch: ['aarch64', 'x86_64']
|
||||
version: ['14.3', '15.0']
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Compile
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
release: ${{ matrix.version }}
|
||||
usesh: true
|
||||
prepare: pkg install -y cmake git ninja
|
||||
run: |
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build --verbose
|
||||
ctest --test-dir build
|
||||
66
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-linux.yml
vendored
Normal file
66
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-linux.yml
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
name: Linux CMake
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
tags-ignore: '*.*'
|
||||
paths:
|
||||
- '.github/workflows/cmake-linux.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/linux/*pp'
|
||||
pull_request:
|
||||
branches: main
|
||||
paths:
|
||||
- '.github/workflows/cmake-linux.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/linux/*pp'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.compiler }}-${{ matrix.version }}
|
||||
runs-on: ubuntu-24.04
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.compiler }}-${{ matrix.version }}
|
||||
cancel-in-progress: true
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- compiler: clang
|
||||
version: 19
|
||||
- compiler: clang
|
||||
version: 20
|
||||
- compiler: clang
|
||||
version: 21
|
||||
- compiler: gcc
|
||||
version: 14
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install clang ${{ matrix.version }}
|
||||
if: ${{ matrix.compiler == 'clang' }}
|
||||
run: wget -qO - https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ matrix.version }} all
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
if [[ "${{ matrix.compiler }}" == "clang" ]]; then
|
||||
export CC=clang-${{ matrix.version }}
|
||||
export CXX=clang++-${{ matrix.version }}
|
||||
export CXXFLAGS="-stdlib=libc++"
|
||||
export LDFLAGS="-fuse-ld=lld -rtlib=compiler-rt -unwindlib=libunwind"
|
||||
else
|
||||
export CC=gcc-${{ matrix.version }}
|
||||
export CXX=g++-${{ matrix.version }}
|
||||
fi
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
- name: Compile
|
||||
run: cmake --build build --verbose
|
||||
|
||||
- name: Test
|
||||
run: ctest --test-dir build
|
||||
52
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-macos.yml
vendored
Normal file
52
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-macos.yml
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
name: macOS CMake
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
tags-ignore: '*.*'
|
||||
paths:
|
||||
- '.github/workflows/cmake-macos.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/osx/*pp'
|
||||
pull_request:
|
||||
branches: main
|
||||
paths:
|
||||
- '.github/workflows/cmake-macos.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/osx/*pp'
|
||||
|
||||
jobs:
|
||||
cmake_build_on_macos:
|
||||
runs-on: macos-15
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install build tools
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
brew update --quiet
|
||||
brew install --force --overwrite cmake llvm lld ninja
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
export LLVM_PREFIX="$(brew --prefix llvm)"
|
||||
export LLD_PREFIX="$(brew --prefix lld)"
|
||||
export CXX="$LLVM_PREFIX/bin/clang++"
|
||||
export CPPFLAGS="-I$LLVM_PREFIX/include"
|
||||
export LDFLAGS="-L$LLVM_PREFIX/lib -L$LLVM_PREFIX/lib/c++ -Wl,-rpath,$LLVM_PREFIX/lib/c++ -fuse-ld=$LLD_PREFIX/bin/ld64.lld"
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
- name: Compile
|
||||
run: cmake --build build --verbose
|
||||
|
||||
- name: Test
|
||||
run: ctest --test-dir build
|
||||
53
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-netbsd.yml
vendored
Normal file
53
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-netbsd.yml
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
name: NetBSD CMake
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
tags-ignore: '*.*'
|
||||
paths:
|
||||
- '.github/workflows/cmake-netbsd.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/netbsd/*pp'
|
||||
pull_request:
|
||||
branches: main
|
||||
paths:
|
||||
- '.github/workflows/cmake-netbsd.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/netbsd/*pp'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: netbsd-${{ matrix.version }}-${{ matrix.arch }}
|
||||
runs-on: ubuntu-24.04
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.arch }}-${{ matrix.version }}
|
||||
cancel-in-progress: true
|
||||
strategy:
|
||||
matrix:
|
||||
arch: ['aarch64', 'amd64']
|
||||
version: ['10.1']
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Compile
|
||||
uses: vmactions/netbsd-vm@v1
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
release: ${{ matrix.version }}
|
||||
usesh: true
|
||||
prepare: |
|
||||
export PATH="/usr/pkg/sbin:/usr/pkg/bin:$PATH"
|
||||
export PKG_PATH="https://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/${{ matrix.arch }}/${{ matrix.version }}/All/"
|
||||
/usr/sbin/pkg_add pkgin
|
||||
pkgin -y install cmake gcc14 git ninja-build
|
||||
run: |
|
||||
export CXX="/usr/pkg/gcc14/bin/g++"
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build --verbose
|
||||
ctest --test-dir build
|
||||
48
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-openbsd.yml
vendored
Normal file
48
libs/external/chat-vault/monitoring/grafana/monitor-tui/.github/workflows/cmake-openbsd.yml
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
name: OpenBSD CMake
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
tags-ignore: '*.*'
|
||||
paths:
|
||||
- '.github/workflows/cmake-openbsd.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/openbsd/*pp'
|
||||
pull_request:
|
||||
branches: main
|
||||
paths:
|
||||
- '.github/workflows/cmake-openbsd.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- 'include/**'
|
||||
- 'src/*pp'
|
||||
- 'src/openbsd/*pp'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: openbsd-${{ matrix.version}}-${{ matrix.arch}}
|
||||
runs-on: ubuntu-24.04
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.arch }}-${{ matrix.version }}
|
||||
cancel-in-progress: true
|
||||
strategy:
|
||||
matrix:
|
||||
arch: ['aarch64', 'x86_64']
|
||||
version: ['7.8']
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Compile
|
||||
uses: vmactions/openbsd-vm@v1
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
release: ${{ matrix.version }}
|
||||
usesh: true
|
||||
prepare: pkg_add cmake git ninja
|
||||
run: |
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build --verbose
|
||||
ctest --test-dir build
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
name: Continuous Build FreeBSD
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/linux/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-freebsd.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/linux/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-freebsd.yml'
|
||||
|
||||
jobs:
|
||||
build-freebsd:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ["clang++", "g++"]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Compile
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
release: '14.3'
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg install -y gmake gcc15 coreutils git lowdown
|
||||
git config --global --add safe.directory /home/runner/work/btop/btop
|
||||
run: |
|
||||
if [ "${{ matrix.compiler }}" == "g++" ]; then
|
||||
CXX=g++15
|
||||
COMPILER=gcc
|
||||
else
|
||||
CXX=clang++
|
||||
COMPILER=llvm
|
||||
fi
|
||||
gmake STATIC=true STRIP=true
|
||||
GIT_HASH=$(git rev-parse --short "$GITHUB_SHA")
|
||||
mv bin/btop bin/btop-"$COMPILER"-"$GIT_HASH"
|
||||
ls -alh bin
|
||||
|
||||
- uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: btop-x86_64-freebsd-14-${{ matrix.compiler }}
|
||||
path: 'bin/*'
|
||||
if-no-files-found: error
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
name: Continuous Build Gpu
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-gpu.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-gpu.yml'
|
||||
|
||||
jobs:
|
||||
gpu_build_linux:
|
||||
runs-on: ubuntu-24.04
|
||||
container: alpine:edge
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install build tools
|
||||
run: apk add --no-cache --update gcc g++ make linux-headers
|
||||
|
||||
- name: Compile
|
||||
run: make CXX=g++ GPU_SUPPORT=true
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
name: Continuous Build Linux
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: main
|
||||
tags-ignore: '*.*'
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-linux.yml'
|
||||
pull_request:
|
||||
branches: main
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-linux.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.toolchain }}
|
||||
cancel-in-progress: true
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
toolchain:
|
||||
- aarch64-unknown-linux-musl
|
||||
- arm-unknown-linux-musleabi
|
||||
- arm-unknown-linux-musleabihf
|
||||
- armv7-unknown-linux-musleabi
|
||||
- armv7-unknown-linux-musleabihf
|
||||
- i586-unknown-linux-musl
|
||||
- i686-unknown-linux-musl
|
||||
- m68k-unknown-linux-musl
|
||||
- mips-unknown-linux-musl
|
||||
- mips-unknown-linux-muslsf
|
||||
- mips64-unknown-linux-musl
|
||||
- mips64el-unknown-linux-musl
|
||||
- mipsel-unknown-linux-musl
|
||||
- mipsel-unknown-linux-muslsf
|
||||
- powerpc-unknown-linux-musl
|
||||
- powerpc64-unknown-linux-musl
|
||||
- powerpc64le-unknown-linux-musl
|
||||
- powerpcle-unknown-linux-musl
|
||||
- riscv32-unknown-linux-musl
|
||||
- riscv64-unknown-linux-musl
|
||||
- s390x-ibm-linux-musl
|
||||
- x86_64-unknown-linux-musl
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install cross toolchain
|
||||
run: |
|
||||
wget -q -P /tmp https://github.com/cross-tools/musl-cross/releases/download/20250929/${{ matrix.toolchain }}.tar.xz
|
||||
wget -q -P /tmp https://github.com/cross-tools/musl-cross/releases/download/20250929/${{ matrix.toolchain }}.tar.xz.sha256
|
||||
echo "$(cat /tmp/${{ matrix.toolchain }}.tar.xz.sha256) /tmp/${{ matrix.toolchain }}.tar.xz" | sha256sum --check --status
|
||||
mkdir -p /opt/x-tools/
|
||||
tar -xf /tmp/${{ matrix.toolchain }}.tar.xz -C /opt/x-tools
|
||||
|
||||
- name: Compile
|
||||
run: CXX=/opt/x-tools/${{ matrix.toolchain }}/bin/${{ matrix.toolchain }}-g++ make STATIC=true STRIP=true
|
||||
|
||||
- name: Create binary artifacts
|
||||
run: |
|
||||
TOOLCHAIN=${{ matrix.toolchain }}
|
||||
GIT_HASH=$(git rev-parse --short "${{ github.sha }}")
|
||||
FILENAME=btop-${TOOLCHAIN/linux-musl/}-$GIT_HASH
|
||||
mv bin/btop bin/$FILENAME
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: btop-${{ matrix.toolchain }}
|
||||
path: '${{ github.workspace }}/bin/*'
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
name: Continuous Build MacOS
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/linux/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-macos.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/linux/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-macos.yml'
|
||||
|
||||
jobs:
|
||||
build-macos:
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
# - {runner: 'macos-13', version: 'Ventura'}
|
||||
- {runner: 'macos-14', version: 'Sonoma'}
|
||||
- {runner: 'macos-15', version: 'Sequoia'}
|
||||
runs-on: ${{ matrix.os.runner }}
|
||||
steps:
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: latest-stable
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install build tools
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
brew update --quiet
|
||||
brew install --force --overwrite gcc@15 lowdown
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
make CXX=$(brew --prefix)/bin/g++-15
|
||||
GIT_HASH=$(git rev-parse --short "$GITHUB_SHA")
|
||||
mv bin/btop bin/btop-arm64-${{ matrix.os.runner }}-${{ matrix.os.version }}-$GIT_HASH
|
||||
ls -alh bin
|
||||
|
||||
- uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: btop-arm64-${{ matrix.os.runner }}-${{ matrix.os.version }}
|
||||
path: 'bin/*'
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
name: Continuous Build NetBSD
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/linux/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-netbsd.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/linux/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-netbsd.yml'
|
||||
|
||||
jobs:
|
||||
build-netbsd:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Compile
|
||||
uses: vmactions/netbsd-vm@v1
|
||||
|
||||
with:
|
||||
release: '10.1'
|
||||
usesh: true
|
||||
prepare: |
|
||||
PATH="/usr/pkg/sbin:/usr/pkg/bin:$PATH"
|
||||
PKG_PATH="https://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/amd64/10.1/All/"
|
||||
export PATH PKG_PATH
|
||||
/usr/sbin/pkg_add pkgin
|
||||
pkgin -y install gmake gcc14 coreutils git
|
||||
git config --global --add safe.directory /home/runner/work/btop/btop
|
||||
run: |
|
||||
gmake CXX=/usr/pkg/gcc14/bin/g++ CXXFLAGS='-DNDEBUG -I/usr/pkg/gcc10/include -I/usr/include -I/usr/pkg/include' STATIC=true STRIP=true
|
||||
GIT_HASH=$(git rev-parse --short "$GITHUB_SHA")
|
||||
mv bin/btop bin/btop-GCC10-"$GIT_HASH"
|
||||
ls -alh bin
|
||||
|
||||
- uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: btop-x86_64-netbsd-9.3
|
||||
path: 'bin/*'
|
||||
if-no-files-found: error
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
name: Continuous Build OpenBSD
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/linux/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-openbsd.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/linux/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/continuous-build-openbsd.yml'
|
||||
|
||||
jobs:
|
||||
build-openbsd:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Compile
|
||||
uses: vmactions/openbsd-vm@v1
|
||||
with:
|
||||
release: '7.8'
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg_add gmake coreutils git lowdown
|
||||
git config --global --add safe.directory /home/runner/work/btop/btop
|
||||
run: |
|
||||
gmake STATIC=true STRIP=true
|
||||
GIT_HASH=$(git rev-parse --short "$GITHUB_SHA")
|
||||
mv bin/btop bin/btop-"$GIT_HASH"
|
||||
|
||||
- uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: btop-x86_64-openbsd-7.8
|
||||
path: 'bin/*'
|
||||
if-no-files-found: error
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
name: 🧪 Test snap can be built on x86_64
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ main ]
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/test-snap-can-build.yml'
|
||||
- 'snap/snapcraft.yaml'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '!src/osx/**'
|
||||
- '!src/freebsd/**'
|
||||
- '!src/netbsd/**'
|
||||
- '!src/openbsd/**'
|
||||
- 'include/**'
|
||||
- 'Makefile'
|
||||
- '.github/workflows/test-snap-can-build.yml'
|
||||
- 'snap/snapcraft.yaml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: snapcore/action-build@v1
|
||||
id: build
|
||||
|
||||
- uses: diddlesnaps/snapcraft-review-action@v1
|
||||
with:
|
||||
snap: ${{ steps.build.outputs.snap }}
|
||||
isClassic: 'false'
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
# gitginore template for creating Snap packages
|
||||
# website: https://snapcraft.io/
|
||||
|
||||
parts/
|
||||
prime/
|
||||
stage/
|
||||
*.snap
|
||||
|
||||
# Snapcraft global state tracking data(automatically generated)
|
||||
# https://forum.snapcraft.io/t/location-to-save-global-state/768
|
||||
/snap/.snapcraft/
|
||||
|
||||
# Source archive packed by `snapcraft cleanbuild` before pushing to the LXD container
|
||||
/*_source.tar.bz2
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Compiled man page
|
||||
btop.1
|
||||
|
||||
build
|
||||
bin
|
||||
btop
|
||||
/obj/
|
||||
config.h
|
||||
.*/
|
||||
|
||||
# Optional libraries
|
||||
lib/rocm_smi_lib
|
||||
|
||||
# Don't ignore .github directory
|
||||
!.github/
|
||||
|
||||
# Ignore files created by Qt Creator
|
||||
*.config
|
||||
*.creator
|
||||
*.creator.user
|
||||
*.creator.user.*
|
||||
*.cflags
|
||||
*.cxxflags
|
||||
*.files
|
||||
*.includes
|
||||
|
||||
# CMake
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
CMakeUserPresets.json
|
||||
|
||||
# CLion
|
||||
cmake-build-*
|
||||
|
|
@ -0,0 +1,624 @@
|
|||
## v1.4.5
|
||||
|
||||
References | Description | Author(s)
|
||||
--- | --- | ---
|
||||
#1254 | Bump bundled fmt to 12.0.0 | @deckstose
|
||||
#1242 | Enable vim movement in help menu | @botantony
|
||||
#948 | Remove reduntant symbols in tree view | @Denizantip
|
||||
#1249 | Use /sys/dev/block/MAJOR:MINOR instead of /sys/block/NAME for disk I/O | @CountBleck
|
||||
#1227 | feat: display CPU power draw & fix GPU+load avg overwriting core info | @Tom94 and @YuriiShkrobut
|
||||
4f5abbb | Fix locale issues | @aristocratos
|
||||
#1165 | Add encode and decode meters on Nvidia GPUs | @sam-kirby
|
||||
#1197 | linux: Battery Time-to-full | @RadsammyT
|
||||
#1203 | Convert ascii escape codes in mountpoint names before reading statvfs | @deckstose
|
||||
#1198 | Fix presets erroring with gpu* usage | @entropylost
|
||||
#1191 | Fix --tty/--no-tty flag having no effect | @deckstose
|
||||
|
||||
## v1.4.4
|
||||
|
||||
References | Description | Author(s)
|
||||
--- | --- | ---
|
||||
#1185 | Fix auto-detection of CPU temp on Ampere boards | @bexcran
|
||||
589c133 | Fixed floating_humanizer() to work correctly when numeric delimiter isn't a dot. | @aristocratos
|
||||
#1157 | Add command line option to set an inital filter | @imwints
|
||||
#1172 | Make 100ms the minimal refresh rate. Exit gracefully if integer conversion in CLI parser fails. | @imwints
|
||||
#1031 | Lock/unlock config to avoid infinite recursion | @Jacajack
|
||||
#1156 | Fix incorrect positioning and start symbol of second title introduced in 2538d89 | @xDMPx
|
||||
ffcd064 | Fix dangling reference warnings for GCC 13 and later | aristocratos
|
||||
|
||||
## v1.4.3
|
||||
|
||||
References | Description | Author(s)
|
||||
--- | --- | ---
|
||||
c3b225f | Revert e266ccd which broke str_to_upper() and str_to_lower() | @aristocratos
|
||||
#1137 | Enable additional checks in libc++ with the new hardening mode | @imwints
|
||||
#1135 | Remove redundant optimization flag | @imwints
|
||||
#1139 | Ignore incomplete filter regex, issue #1133 | @imwints
|
||||
|
||||
## v1.4.2
|
||||
|
||||
References | Description | Author(s)
|
||||
--- | --- | ---
|
||||
f1482fe | Fix process arguments appearing outside proc box by replacing ASCII control codes with blankspace, issue #1080 | @aristocratos
|
||||
#1130 | Fix problems shown by clang-tidy's performance checks | @imwints
|
||||
#1120 | Fix wrong error message and documentation of renamed option --utf-force | @t-webber @imwints
|
||||
#1128 | Flatten cmake module path | @imwints
|
||||
#1129 | CMake: Remove option to use mold | @imwints
|
||||
#1047 | Update Terminus font link, fix typo, spelling, and grammar | @QinCai-rui
|
||||
#929 | Please clang with sanitizers | @bad-co-de
|
||||
#1126 | Fix MacOS tree-mode + aggregate memory/thread scaling issue | @xaskii
|
||||
#993 | Fix typo: Mhz -> MHz | @NyCodeGHG
|
||||
|
||||
## v1.4.1
|
||||
|
||||
References | Description | Author(s)
|
||||
--- | --- | ---
|
||||
#1111 #1112 | Various code fixes | @imwints
|
||||
#930 #931 | Various code fixes | @bad-co-de
|
||||
#1061 | Fixed typo | @polluks
|
||||
#1110 | Move the config parser in it's own module | @imwints
|
||||
#1101 | Adding a menu option to show bitrates in base 10 separate from the setting to show bytes/bits in base 10 | @georgev93
|
||||
#1079 | Allow MidnightBSD to build btop using the existing freebsd support. | @laffer1
|
||||
#1098 | Use XDG_STATE_HOME to save logs | @imwints
|
||||
#1092 | Bump CMake version to 3.25 required for LINUX variable | @imwints
|
||||
#1058 | Replace brackets with arrows in net and proc box | @taha-yassine
|
||||
#1091 | Bump bundled fmt to 11.1.4 | @imwints
|
||||
#725 | cmake: link to CMAKE_DL_LIBS | @alalazo
|
||||
#990 | Fix phoenix-night.theme marked as executable | @sertonix
|
||||
#1034 | Add Kanagawa-lotus and Kanagawa-wave themes | @philikarus
|
||||
#973 | Bump NetBSD version to 10.1 and FreeBSD version to 14.2. | @fraggerfox
|
||||
#1072 | Add dark version of adwaita theme: adwaita-dark | @k0tran
|
||||
#1036 | Resetting last selection on page navigation in optionsMenu to avoid unordered_map error | @seth-wood
|
||||
#1029 | Share the CPU name trimming code between platforms | @yarrick
|
||||
#1033 | Update Ryzen name trimming | @yarrick
|
||||
#1030 | Drop macos 12 build, add v14 and v15 | @yarrick
|
||||
#1028 | Fix cmake-macos workflow | @yarrick
|
||||
#1027 | Bump version of deprecated upload-artifact step | @yarrick
|
||||
#1025 | Update obsolete egrep call | @tywkeene
|
||||
b52069c | Fix menu crash when GPU_SUPPORT=false, issue #989 | @aristocratos
|
||||
#961 | Add 'Everforest Ligth Medium' theme | @mstuttgart
|
||||
#960 | Support intel GPUs before Gen-6 (patch from upstream) | @w8jcik
|
||||
#958 | intel_name_lookup_shim.c (get_intel_device_name): Fix SEGFAULT | @artyom-poptsov
|
||||
2e7208d | Fix rsmi_measure_pcie_speeds not saving, issue #934 | @aristocratos
|
||||
f3446ed | Show GPU Watt fractions when below 100W | @aristocratos
|
||||
|
||||
| + more from @imwints @aristocratos
|
||||
|
||||
Big thanks to @imwints for helping out with project maintenance, PR reviews and merging!
|
||||
|
||||
## v1.4.0
|
||||
|
||||
References | Description | Author(s)
|
||||
--- | --- | ---
|
||||
#703 | NetBSD Support | @fraggerfox
|
||||
#903 | Intel GPU support | @bjia56
|
||||
161e8f4 | Added warnings when toggling boxes and terminal size is to small | @aristocratos
|
||||
4210f5f | Fix missing core percentages, issue #792 | @aristocratos
|
||||
35857f8 | Various fixes for drawing GPU related information | @aristocratos
|
||||
#879 | fix divide 0 error when caculating disk usage percentage (#791) | @flylai
|
||||
#884 | fix io_graph_speeds parsing | @feihtthief
|
||||
#863 | V1 of Phoenix Night theme | @Firehawke
|
||||
3f384c0 | Fixed missing CPU core temps when too small to show core temp graphs, issues #792 #867 | @aristocratos
|
||||
97d2fb5 | Fixed missing IO graphs in IO mode, issue #867 | @aristocratos
|
||||
#840 | fix zero temp (#467) | @joske
|
||||
#850 | Fix comments (parsing) in theme files | @acidghost
|
||||
#806 | Add regex filtering | @imwints
|
||||
#836 | Fix typo in file existences check for voltage_now | @vsey
|
||||
#835 | Show time in days when remaining battery exceeds an estimation of 24h | @imwints
|
||||
#819 | (AMD Gpu) fix pwr_usage not being defined correctly during rsmi collection | @kalkafox
|
||||
#831 | macOS: fix crash if there exists a uid not associated with any user | @thecoder-001
|
||||
#796 | Fix rsmi device name buffer size | @davc0n
|
||||
#807 | Add gruvbox_light theme | @kk9uk
|
||||
#724 | Create man page for btop in Markdown | @ottok
|
||||
#734 | Include metadata in binary version output `btop --version` | @imwints
|
||||
#771 | collect: Fix reading of battery power draw on Linux | @Derppening
|
||||
|
||||
## v1.3.2
|
||||
|
||||
Description | Author(s) | References
|
||||
--- | --- | ---
|
||||
fix: Can't detect librocm 6.0.x | @imwints, @aristocratos | #761
|
||||
|
||||
## v1.3.1
|
||||
|
||||
Description | Author(s) | References
|
||||
--- | --- | ---
|
||||
GPU: Added support for dynamic loading of ROCm v6 libraries | @aristocratos, @fxzjshm | 5511131, #737
|
||||
Increase max network interface name to 15 | @tessus | #714
|
||||
Fix OpenBSD UTF-8 locale detection | @lcheylus, @imwints | #753, #717
|
||||
Add hot-reloading of config file with CTRL+R or SIGUSR2 signal | @MartinPit | #722
|
||||
Add battery power draw for linux and freebsd | @vsey | #689
|
||||
Fix crash caused by string exception when cpu clock is exactly between 999.5 and 999.9 Mhz | @rkmcode | #735
|
||||
Write newline at end of config file | @planet36 | #743
|
||||
Add theme based on Everforest Dark Medium palette | @M-Sviridov | #746
|
||||
fix: don't mangle memory for zombie processes | @joske | #747
|
||||
Share common code from collect | @imwints | #756
|
||||
Fixed incorrect used and available memory for OSX | | 4461a43
|
||||
|
||||
## v1.3.0
|
||||
|
||||
* Added Gpu Support Linux | @romner-set | PR #529
|
||||
|
||||
* Added platform support for OpenBSD | @joske | PR #607
|
||||
|
||||
* Enable macos clang | @muneebmahmed | PR #666
|
||||
|
||||
* Fix Apple Silicon CPUs misprinted | @masiboss | PR #679
|
||||
|
||||
* Cmake support for MacOS | @imwints | PR #675
|
||||
|
||||
* Elementarish theme: color update according to Elementary palette | @stradicat | PR #660
|
||||
|
||||
* Add alternative key codes for Delete, Insert, Home, End | @ivanp7 | PR #659
|
||||
|
||||
* Fix scrollbar not clearing sometimes. | @DecklynKern | PR #643
|
||||
|
||||
* Add keybind for toggling memory display mode in PROC box | @rahulaggarwal965 | PR #623
|
||||
|
||||
* Minor string initialization improvement | @imwints | PR #636
|
||||
|
||||
* Made disks statvfs logic asynchronous. | @crestfallnatwork | PR #633
|
||||
|
||||
* Fix signal list on non-linux/weird linux platforms | @lvxnull | PR #630
|
||||
|
||||
* Add option to accumulate a child's resources in parent in tree-view | @imwints | PR #618
|
||||
|
||||
* Add CMake support for Linux | @imwints | PR #589
|
||||
|
||||
* Horizon theme | @SidVeld | PR #610
|
||||
|
||||
* Fix short conversion of 1000-1023 *iB | @scorpion-26 | #609
|
||||
|
||||
* Fix integer overflows in btop_collect.cpp | @dorrellmw | #546
|
||||
|
||||
* Support compiling with LLVM | @imwints | #510
|
||||
|
||||
* Fix getting zfs pool name with '.' char in freebsd | @jfouquart | #602
|
||||
|
||||
* [macos/freebsd] support gcc13 | @joske | #600
|
||||
|
||||
* FreeBSD swap info | @rrveex | #560
|
||||
|
||||
* Create adwaita.theme | @flipflop133 | #485
|
||||
|
||||
* Try get terminal size of "/dev/tty" if stdout fails | @imwints | PR #627
|
||||
|
||||
* Refresh rate program argument | @imwints | PR #640
|
||||
|
||||
* Improved error handling when determining the config directory | @imwints | #652
|
||||
|
||||
* Use native POSIX polling syscalls to read input | @lvxnull | #624
|
||||
|
||||
* Conditional compile on Big Sur and up | @joske | PR #690
|
||||
|
||||
+ Various fixes by @imwints, @simplepad, @joske, @gwena, @cpalv, @iambeingtracked, @mattico, @NexAdn
|
||||
|
||||
## v1.2.13
|
||||
|
||||
* Makefile: VERBOSE=true flag for Makefile to display all compiler commands and fixed so already set CXXFLAGS and LDFLAGS are displayed.
|
||||
|
||||
* Makefile: Added autodetection for gcc12 to make compiling on macos Ventura easier.
|
||||
|
||||
* Changed: Reverted back to sysconf(_SC_NPROCESSORS_ONLN) for Cpu core count ant let the new dynamic update fix if cores are turned on later
|
||||
|
||||
* Fixed: Ignore disks that fails in statvfs64() to avoid slowdowns and possible crashes.
|
||||
|
||||
* Fixed: Moved up get_cpuHz() in the execution order to get better cpu clock reading.
|
||||
|
||||
* Added: proc tree view: if there's more than 40 width left, try to print full cmd, by @Superty
|
||||
|
||||
* Fixed: Show the first IP of the interface in NET box instead of the last, by @correabuscar
|
||||
|
||||
* Changed: Replace getnameinfo with inet_ntop [on Linux], by @correabuscar
|
||||
|
||||
* Fixed: Not picking up last username from /etc/passwd
|
||||
|
||||
* Fixed: Process nice value underflowing, issue #461
|
||||
|
||||
* Changed: Replace getnameinfo with inet_ntop [on FreeBSD], by @correabuscar
|
||||
|
||||
* Changed: Replace getnameinfo with inet_ntop [on macos], by @correabuscar
|
||||
|
||||
## v1.2.12
|
||||
|
||||
* Added: Dynamic updating of max number of CPU cores.
|
||||
|
||||
## v1.2.11
|
||||
|
||||
* Fixed: Number of cores wrongly detected for Ryzen in rare cases.
|
||||
|
||||
## v1.2.10
|
||||
|
||||
* Fixed: Process tree filtering not case insensitive
|
||||
|
||||
* Added: Paper theme, by @s6muel
|
||||
|
||||
* Fixed: Extra checks to avoid crash on trying to replace empty strings in tree mode
|
||||
|
||||
* Fixed: Crashing when cores are offline
|
||||
|
||||
* Fixed: Cpu::collect() core count counter...
|
||||
|
||||
* Changed: Using sysconf(_SC_NPROCESSORS_CONF) for number of cores instead of sysconf(_SC_NPROCESSORS_ONLN)
|
||||
|
||||
* Maintenance: Code cleanup, by @stefanos82
|
||||
|
||||
## v1.2.9
|
||||
|
||||
* Fixed: Memory values not clearing properly when not in graph mode in mem box
|
||||
|
||||
* Changed: kyli0x theme color update, by @kyli0x
|
||||
|
||||
* Added: Elementarish theme, by @dennismayr
|
||||
|
||||
* Added: key "?" to see help, by @mohi001
|
||||
|
||||
* Added: solarized_light theme, by @Fingerzam
|
||||
|
||||
* Changed: Made ZFS stats collection compatible with zfs_pools_only option, by @simplepad
|
||||
|
||||
* Changed: Rewrite of process sorting and tree generation including fixes for tree sorting and mouse support
|
||||
|
||||
* Added: Option to hide the small cpu graphs for processes
|
||||
|
||||
* Changed: Small graphs now show colors for each character
|
||||
|
||||
* Fixed: Getting selfpath on macos (fix for finding theme folder)
|
||||
|
||||
## v1.2.8
|
||||
|
||||
* Added: Support for ZFS pool io stats monitoring, by @simplepad
|
||||
|
||||
* Added: Filtering of kernel processes, by @0xJoeMama
|
||||
|
||||
* Added: New theme everforest-dark-hard, by @iambeingtracked
|
||||
|
||||
* Added: New theme tomorrow-night, by @appuchias
|
||||
|
||||
* Changed: Disable battery monitoring if it fails instead of exiting
|
||||
|
||||
## v1.2.7
|
||||
|
||||
* Fixed: Disk IO stats for individual partitions instead of whole disk (Linux)
|
||||
|
||||
* Added: Case insensitive process filtering, by @abrasumente233
|
||||
|
||||
* Added: Include ZFS ARC in cached/available memory on Linux, by @mattico
|
||||
|
||||
* Added: Desktop entry and icons, by @yonatan8070
|
||||
|
||||
* Fixed: Net sync scale bug
|
||||
|
||||
* Added: tokyo-night & tokyo-storm themes, by @Schievel1
|
||||
|
||||
## v1.2.6
|
||||
|
||||
* Fixed: Wrong memory unit when shorten and size is less than 10, by @mohi001
|
||||
|
||||
* Fixed: Use cpu cores average temp if missing cpu package temp for FreeBSD
|
||||
|
||||
* Changed: Enter symbol to a more common variant
|
||||
|
||||
## v1.2.5
|
||||
|
||||
* Fixed: Fallback to less accurate UTF8 char count if conversion to wstring fails
|
||||
|
||||
* Fixed: Small ui fixes for mem and disks
|
||||
|
||||
* Added: New theme HotPurpleTrafficLight, by @pallebone
|
||||
|
||||
* Fixed: title_left symbol between auto and zero in the net box is not displayed, by @mrdotx
|
||||
|
||||
* Fixed: Mouse mappings for net box
|
||||
|
||||
## v1.2.4
|
||||
|
||||
* Optimization: Proc::draw()
|
||||
|
||||
* Fixed: Ignore duplicate disks with same mountpoint
|
||||
|
||||
* Changed: Restrict command line for processes to 1000 characters to fix utf8 conversion errors
|
||||
|
||||
* Added: add "g" and "G" to vim keys, by @mohi001
|
||||
|
||||
## v1.2.3
|
||||
|
||||
* Changed: floating_humanizer() now show fractions when shortened and value is < 10
|
||||
|
||||
* Fixed: Process tree not redrawing properly
|
||||
|
||||
* Fixed: string to wstring conversion crash when string is too big
|
||||
|
||||
## v1.2.2
|
||||
|
||||
* Changed: Reverted uncolor() back to using regex to fix delay in opening menu when compiled with musl
|
||||
|
||||
* Added: Toggle for showing free disk space for privileged or normal users
|
||||
|
||||
* Added: Clarification on signal screen that number can be manually entered
|
||||
|
||||
## v1.2.1
|
||||
|
||||
* Added: Arrow only after use of "f" when filtering processes, by @NavigationHazard
|
||||
|
||||
* Fixed: Fx::uncolor not removing all escapes
|
||||
|
||||
* Fixed: Text alignment for popup boxes
|
||||
|
||||
* Fixed: Terminal resize warning getting stuck
|
||||
|
||||
* Removed: Unnecessary counter for atomic_lock
|
||||
|
||||
* Added: Percentage progress to Makefile
|
||||
|
||||
* Fixed: Alignment of columns in proc box when wide UTF8 characters are used
|
||||
|
||||
* Fixed: Battery meter draw fix
|
||||
|
||||
## v1.2.0
|
||||
|
||||
* Added: Support for FreeBSD, by @joske and @aristocratos
|
||||
|
||||
* Fixed (again): Account for system rolling over net speeds in Net::collect()
|
||||
|
||||
* Added: Theme gruvbox_material_dark, by @marcoradocchia
|
||||
|
||||
* Added: Option for base 10 bytes/bits
|
||||
|
||||
## v1.1.5
|
||||
|
||||
* Fixed: Account for system rolling over net speeds in Net::collect()
|
||||
|
||||
## v1.1.4
|
||||
|
||||
* Fixed: Create dependency files in build directory when compiling, by @stwnt
|
||||
|
||||
* Fixed: fix CPU temp fallback on macOS, by @joske
|
||||
|
||||
* Changed: From rng::sort() to rng::stable_sort() for more stability
|
||||
|
||||
* Fixed: in_avail() can always be zero, by @pg83
|
||||
|
||||
## v1.1.3
|
||||
|
||||
* Added: New theme ayu, by @AlphaNecron
|
||||
|
||||
* Added: New theme gruvbox_dark_v2, by @pietryszak
|
||||
|
||||
* Fixed: Macos cpu coretemp for Intel, by @joske
|
||||
|
||||
* Added: New theme OneDark, by @vtmx
|
||||
|
||||
* Fixed: Fixed network graph scale int rollover
|
||||
|
||||
* Fixed: Suspected possibility of very rare stall in Input::clear()
|
||||
|
||||
## v1.1.2
|
||||
|
||||
* Fixed: SISEGV on macos Mojave, by @mgradowski
|
||||
|
||||
* Fixed: Small optimizations and fixes to Mem::collect() and Input::get()
|
||||
|
||||
* Fixed: Wrong unit for net_upload and net_download in config menu
|
||||
|
||||
* Fixed: UTF-8 detection on macos
|
||||
|
||||
* Fixed: coretemp iteration due to missing tempX_input, by @KFilipek
|
||||
|
||||
* Fixed: coretemp ordering
|
||||
|
||||
## v1.1.1
|
||||
|
||||
* Added: Partial static build (libgcc, libstdc++) for macos
|
||||
|
||||
* Changed: Continuous build macos switched to OSX 11.6 (Big Sur) and partial static build
|
||||
|
||||
* Changed: Release binaries for macos switched to OSX 12 (Monterey) and partial static build
|
||||
|
||||
## v1.1.0
|
||||
|
||||
* Added: Support for OSX, by @joske and @aristocratos
|
||||
|
||||
## v1.0.24
|
||||
|
||||
* Changed: Collection ordering
|
||||
|
||||
* Fixed: Restore all escape seq mouse modes on exit
|
||||
|
||||
* Fixed: SIGINT not cleaning up on exit
|
||||
|
||||
## v1.0.23
|
||||
|
||||
* Fixed: Config parser missing first value when not including version header
|
||||
|
||||
* Fixed: Vim keys menu lists selection
|
||||
|
||||
* Fixed: Stall when clearing input queue on exit and queue is >1
|
||||
|
||||
* Fixed: Inconsistent behaviour of "q" key in the menus
|
||||
|
||||
## v1.0.22
|
||||
|
||||
* Fixed: Bad values for disks and network on 32-bit
|
||||
|
||||
## v1.0.21
|
||||
|
||||
* Fixed: Removed extra spaces in cpu name
|
||||
|
||||
* Added: / as alternative bind for filter
|
||||
|
||||
* Fixed: Security issue when running with SUID bit set
|
||||
|
||||
## v1.0.20
|
||||
|
||||
* Added: Improved cpu sensor detection for Ryzen Mobile, by @adnanpri
|
||||
|
||||
* Changed: Updated makefile
|
||||
|
||||
* Changed: Regex for Fx::uncolor() changed to string search and replace
|
||||
|
||||
* Changed: Removed all use of regex with dedicated string functions
|
||||
|
||||
## v1.0.19
|
||||
|
||||
* Fixed: Makefile now tests compiler flag compatibility
|
||||
|
||||
## v1.0.18
|
||||
|
||||
* Fixed: Makefile g++ -dumpmachine failure to get platform on some distros
|
||||
|
||||
## v1.0.17
|
||||
|
||||
* Changed: Reverted mutexes back to custom atomic bool based locks
|
||||
|
||||
* Added: Static binaries switched to building with musl + more platforms, by @jan-guenter
|
||||
|
||||
* Fixed: Improved battery detection, by @jan-guenter
|
||||
|
||||
* Added: Displayed battery selectable in options menu
|
||||
|
||||
* Fixed: Battery error if non existent battery named is entered
|
||||
|
||||
## v1.0.16
|
||||
|
||||
* Fixed: atomic_wait() and atomic_lock{} use cpu pause instructions instead of thread sleep
|
||||
|
||||
* Fixed: Swapped from atomic bool spinlocks to mutexes to fix rare deadlock
|
||||
|
||||
* Added: Continuous Build workflow for OSX branch, by @ShrirajHegde
|
||||
|
||||
* Changed: Reverted thread mutex lock to atomic bool with wait and timeout
|
||||
|
||||
* Changed: Removed unnecessary async threads in Runner thread
|
||||
|
||||
* Added: Try to restart secondary thread in case of stall and additional error checks for ifstream in Proc::collect()
|
||||
|
||||
* Fixed: change [k]ill to [K]ill when enabling vim keys, by @jlopezcur
|
||||
|
||||
## v1.0.15
|
||||
|
||||
* Fixed: Extra "root" partition when running in snap
|
||||
|
||||
* Changed: Limit atomic_wait() to 1000ms to fix rare stall
|
||||
|
||||
* Fixed: Removed unneeded lock in Runner::run()
|
||||
|
||||
* Added: Toggle in options for enabling directional vim keys "h,j,k,l"
|
||||
|
||||
## v1.0.14
|
||||
|
||||
* Changed: Total system memory is checked at every update instead of once at start
|
||||
|
||||
* Added: Continuous Build workflow, by @ShrirajHegde
|
||||
|
||||
* Fixed: Uid -> User fallback to getpwuid() if failure for non static builds
|
||||
|
||||
* Fixed: snap root disk and changed to compiler flags instead of env variables for detection
|
||||
|
||||
* Added: Development branch for OSX, by @joske
|
||||
|
||||
## v1.0.13
|
||||
|
||||
* Changed: Graph empty symbol is now regular whitespace
|
||||
|
||||
## v1.0.12
|
||||
|
||||
* Fixed: Exception handling for faulty net download/upload speed
|
||||
|
||||
* Fixed: Cpu percent formatting if over 10'000
|
||||
|
||||
## v1.0.11
|
||||
|
||||
* Changed: atomic_wait to use while loop instead of wait() because of rare stall when a signal handler is triggered while waiting
|
||||
|
||||
* Fixed: Get real / mountpoint when running inside snap
|
||||
|
||||
* Fixed: UTF8 set LANG and LC_ALL to empty before UTF8 search and fixed empty error msg on exit before signal handler init
|
||||
|
||||
* Changed: Init will continue with a warning if UTF-8 locale are detected and it fails to set the locale
|
||||
|
||||
## v1.0.10
|
||||
|
||||
* Added: Wait for terminal size properties to be available at start
|
||||
|
||||
* Changed: Stop second thread before updating terminal size variables
|
||||
|
||||
* Changed: Moved check for valid terminal dimensions to before platform init
|
||||
|
||||
* Added: Check for empty percentage deques
|
||||
|
||||
* Changed: Cpu temp values check for existing values
|
||||
|
||||
* Fixed: Cpu percent cutting off above 1000 percent and added scaling with "k" prefix above 10'000
|
||||
|
||||
* Fixed: Crash when rapidly resizing terminal at start
|
||||
|
||||
## v1.0.9
|
||||
|
||||
* Added: ifstream check and try-catch for stod() in Tools::system_uptime()
|
||||
|
||||
* Fixed: Freeze on cin.ignore()
|
||||
|
||||
## v1.0.8
|
||||
|
||||
* Fixed: Additional NULL checks in UTF-8 detection
|
||||
|
||||
* Changed: Makefile: Only look for g++-11 if CXX=g++
|
||||
|
||||
* Fixed: Missing NULL check for ttyname
|
||||
|
||||
* Changed: Only log tty name if known
|
||||
|
||||
## v1.0.7
|
||||
|
||||
* Fixed: Crash when opening menu at too small size
|
||||
|
||||
* Fixed: Cores not constrained to cpu box and core numbers above 100 cut off
|
||||
|
||||
* Fixed: Scrollbar position incorrect in small lists and selection not working when filtering
|
||||
|
||||
## v1.0.6
|
||||
|
||||
* Fixed: Check that getenv("LANG") is not NULL in UTF-8 check
|
||||
|
||||
* Fixed: Processes not completely hidden when collapsed in tree mode
|
||||
|
||||
* Fixed: Changed wrong filename error.log to btop.log
|
||||
|
||||
## v1.0.5
|
||||
|
||||
* Fixed: Load AVG sizing when hiding temperatures
|
||||
|
||||
* Fixed: Sizing constraints bug on start and boxes can be toggled from size error screen
|
||||
|
||||
* Fixed: UTF-8 check crashing if LANG was set to non existent locale
|
||||
|
||||
## v1.0.4
|
||||
|
||||
* Fixed: Use /proc/pid/statm if RSS memory from /proc/pid/stat is faulty
|
||||
|
||||
## v1.0.3
|
||||
|
||||
* Fixed: stoi 0 literal pointer to nullptr and added more clamping for gradient array access
|
||||
|
||||
## v1.0.2
|
||||
|
||||
* Fixed: ARCH detection in Makefile
|
||||
|
||||
* Fixed: Color gradient array out of bounds, added clamp 0-100 for cpu percent values
|
||||
|
||||
* Fixed: Menu size and preset size issues and added warnings for small terminal size
|
||||
|
||||
* Fixed: Options menu page selection alignment
|
||||
|
||||
## v1.0.1
|
||||
|
||||
* Fixed: UTF-8 check to include UTF8
|
||||
|
||||
* Fixed: Added thread started check before joining in clean_quit()
|
||||
|
||||
* Fix documentation of --utf-force in README and --help. by @purinchu
|
||||
|
||||
## v1.0.0
|
||||
|
||||
* First release for Linux
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# CMake configuration for btop
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
|
||||
# Disable in-source builds since they would override the Makefile
|
||||
if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
message(FATAL_ERROR "In-source builds are not allowed")
|
||||
endif()
|
||||
|
||||
project("btop"
|
||||
DESCRIPTION "A monitor of resources"
|
||||
HOMEPAGE_URL "https://github.com/aristocratos/btop"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
include(CheckIPOSupported)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
# Make our Find<Package>.cmake files available
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_COLOR_DIAGNOSTICS ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
option(BTOP_STATIC "Link btop statically" OFF)
|
||||
option(BTOP_GPU "Enable GPU support" ON)
|
||||
cmake_dependent_option(BTOP_RSMI_STATIC "Link statically to ROCm SMI" OFF "BTOP_GPU" OFF)
|
||||
|
||||
# Enable LTO in release builds by default
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Rel(ease|WithDebInfo)")
|
||||
option(BTOP_LTO "Enable LTO" ON)
|
||||
else()
|
||||
option(BTOP_LTO "Enable LTO" OFF)
|
||||
endif()
|
||||
|
||||
if(BTOP_STATIC AND NOT APPLE)
|
||||
# Set this before calling find_package
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
|
||||
add_executable(btop src/main.cpp)
|
||||
add_library(libbtop OBJECT
|
||||
src/btop.cpp
|
||||
src/btop_cli.cpp
|
||||
src/btop_config.cpp
|
||||
src/btop_draw.cpp
|
||||
src/btop_input.cpp
|
||||
src/btop_menu.cpp
|
||||
src/btop_shared.cpp
|
||||
src/btop_theme.cpp
|
||||
src/btop_tools.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(btop libbtop)
|
||||
|
||||
if(BTOP_LTO)
|
||||
check_ipo_supported()
|
||||
set_target_properties(btop PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
|
||||
set_target_properties(libbtop PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
target_sources(libbtop PRIVATE src/osx/btop_collect.cpp src/osx/sensors.cpp src/osx/smc.cpp)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
|
||||
target_sources(libbtop PRIVATE src/freebsd/btop_collect.cpp)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||
target_sources(libbtop PRIVATE src/openbsd/btop_collect.cpp src/openbsd/sysctlbyname.cpp)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
|
||||
target_sources(libbtop PRIVATE src/netbsd/btop_collect.cpp)
|
||||
elseif(LINUX)
|
||||
target_sources(libbtop PRIVATE src/linux/btop_collect.cpp)
|
||||
if(BTOP_GPU)
|
||||
add_subdirectory(src/linux/intel_gpu_top)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "${CMAKE_SYSTEM_NAME} is not supported")
|
||||
endif()
|
||||
|
||||
# Generate build info
|
||||
execute_process(
|
||||
COMMAND "git" "rev-parse" "--short" "HEAD"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE GIT_COMMIT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
|
||||
set(CONFIGURE_COMMAND
|
||||
"cmake -DBTOP_STATIC=${BTOP_STATIC} -DBTOP_GPU=${BTOP_GPU}"
|
||||
)
|
||||
get_filename_component(CXX_COMPILER_BASENAME "${CMAKE_CXX_COMPILER}" NAME)
|
||||
set(COMPILER "${CXX_COMPILER_BASENAME}")
|
||||
set(COMPILER_VERSION "${CMAKE_CXX_COMPILER_VERSION}")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY IMMEDIATE)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CheckCXXSymbolExists)
|
||||
|
||||
check_cxx_source_compiles(
|
||||
"
|
||||
#include <version>
|
||||
#if __cpp_lib_optional < 202110L
|
||||
#error \"Missing __cpp_lib_optional < 202110L\"
|
||||
#endif
|
||||
int main() { return 0; }
|
||||
"
|
||||
HAS_CXX_OPTIONAL_MONADS
|
||||
)
|
||||
if(NOT HAS_CXX_OPTIONAL_MONADS)
|
||||
message(FATAL_ERROR "The compiler doesn't support std::optional::and_then")
|
||||
endif()
|
||||
check_cxx_symbol_exists("__cpp_lib_expected" "version" HAS_CXX_EXPECTED)
|
||||
if(NOT HAS_CXX_EXPECTED)
|
||||
message(FATAL_ERROR "The compiler doesn't support std::expected")
|
||||
endif()
|
||||
check_cxx_symbol_exists("__cpp_lib_ranges" "version" HAS_CXX_RANGES)
|
||||
if(NOT HAS_CXX_RANGES)
|
||||
message(FATAL_ERROR "The compiler doesn't support std::ranges")
|
||||
endif()
|
||||
check_cxx_symbol_exists("__cpp_lib_ranges_to_container" "version" HAS_CXX_RANGES_TO_CONTAINER)
|
||||
if(NOT HAS_CXX_RANGES_TO_CONTAINER)
|
||||
message(FATAL_ERROR "The compiler doesn't support std::ranges::to")
|
||||
endif()
|
||||
check_cxx_symbol_exists("__cpp_lib_string_contains" "version" HAS_CXX_STRING_CONTAINS)
|
||||
if(NOT HAS_CXX_STRING_CONTAINS)
|
||||
message(FATAL_ERROR "The compiler doesn't support std::string::contains")
|
||||
endif()
|
||||
|
||||
target_compile_options(libbtop PUBLIC -Wall -Wextra -Wpedantic)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if(NOT APPLE)
|
||||
target_compile_options(libbtop PUBLIC -fstack-clash-protection)
|
||||
endif()
|
||||
check_cxx_compiler_flag(-fstack-protector HAS_FSTACK_PROTECTOR)
|
||||
if(HAS_FSTACK_PROTECTOR)
|
||||
target_compile_options(libbtop PUBLIC -fstack-protector)
|
||||
endif()
|
||||
check_cxx_compiler_flag(-fcf-protection HAS_FCF_PROTECTION)
|
||||
if(HAS_FCF_PROTECTION)
|
||||
target_compile_options(libbtop PUBLIC -fcf-protection)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(libbtop PUBLIC
|
||||
FMT_HEADER_ONLY
|
||||
_FILE_OFFSET_BITS=64
|
||||
$<$<CONFIG:Debug>:_GLIBCXX_ASSERTIONS _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG>
|
||||
)
|
||||
|
||||
target_include_directories(libbtop SYSTEM PUBLIC include)
|
||||
|
||||
# Enable pthreads
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(libbtop Threads::Threads)
|
||||
|
||||
# SQLite3 for AltData
|
||||
find_package(SQLite3 REQUIRED)
|
||||
target_link_libraries(libbtop SQLite::SQLite3)
|
||||
|
||||
# Enable GPU support
|
||||
if(LINUX AND BTOP_GPU)
|
||||
target_compile_definitions(libbtop PUBLIC GPU_SUPPORT)
|
||||
|
||||
if(BTOP_RSMI_STATIC)
|
||||
# ROCm doesn't properly add it's folders to the module path if `CMAKE_MODULE_PATH` is already
|
||||
# set
|
||||
# We could also manually append ROCm's path here
|
||||
set(_CMAKE_MODULE_PATH CMAKE_MODULE_PATH)
|
||||
unset(CMAKE_MODULE_PATH)
|
||||
|
||||
# NOTE: This might be problematic in the future if other sub projects depend on this or if
|
||||
# btop starts producing libraries
|
||||
# Build a static ROCm library
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(lib/rocm_smi_lib EXCLUDE_FROM_ALL)
|
||||
|
||||
add_library(ROCm INTERFACE)
|
||||
# Export ROCm's properties to a target
|
||||
target_compile_definitions(ROCm INTERFACE RSMI_STATIC)
|
||||
target_include_directories(ROCm INTERFACE lib/rocm_smi_lib/include)
|
||||
target_link_libraries(ROCm INTERFACE rocm_smi64)
|
||||
|
||||
set(CMAKE_MODULE_PATH _CMAKE_MODULE_PATH)
|
||||
|
||||
target_link_libraries(libbtop ROCm)
|
||||
endif()
|
||||
if(NOT BTOP_STATIC)
|
||||
target_link_libraries(libbtop ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BTOP_STATIC)
|
||||
target_compile_definitions(libbtop PUBLIC STATIC_BUILD)
|
||||
target_link_options(libbtop PUBLIC -static LINKER:--fatal-warnings)
|
||||
endif()
|
||||
|
||||
# Other platform dependent flags
|
||||
if(APPLE)
|
||||
target_link_libraries(libbtop
|
||||
$<LINK_LIBRARY:FRAMEWORK,CoreFoundation> $<LINK_LIBRARY:FRAMEWORK,IOKit>
|
||||
)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
|
||||
# Avoid version mismatch for libstdc++ when a specific version of GCC is installed and not the
|
||||
# default one since all use the default ones RPATH
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
string(REGEX MATCH "^[0-9]+" GCC_VERSION_MAJOR "${CMAKE_CXX_COMPILER_VERSION}")
|
||||
set_target_properties(btop PROPERTIES
|
||||
INSTALL_RPATH "/usr/local/lib/gcc${GCC_VERSION_MAJOR}"
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
)
|
||||
|
||||
# The gcc compiler wrapper doesn't add '--eh-frame-hdr' on FreeBSD with static builds
|
||||
# https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=278551
|
||||
if(BTOP_STATIC)
|
||||
target_link_options(libbtop PUBLIC LINKER:--eh-frame-hdr)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(devstat REQUIRED)
|
||||
find_package(kvm REQUIRED)
|
||||
target_link_libraries(libbtop devstat::devstat kvm::kvm)
|
||||
if(BTOP_STATIC)
|
||||
find_package(elf REQUIRED)
|
||||
target_link_libraries(libbtop elf::elf)
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
target_compile_options(libbtop PUBLIC -static-libstdc++)
|
||||
endif()
|
||||
find_package(kvm REQUIRED)
|
||||
target_link_libraries(libbtop kvm::kvm)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
target_compile_options(libbtop PUBLIC -static-libstdc++)
|
||||
endif()
|
||||
find_package(kvm REQUIRED)
|
||||
find_package(proplib REQUIRED)
|
||||
target_link_libraries(libbtop kvm::kvm proplib::proplib)
|
||||
endif()
|
||||
|
||||
# Check if lowdown is installed
|
||||
find_program(LOWDOWN_EXECUTABLE lowdown)
|
||||
|
||||
if(LOWDOWN_EXECUTABLE)
|
||||
# Custom target to compile Markdown to man page using lowdown
|
||||
add_custom_command(
|
||||
OUTPUT btop.1
|
||||
COMMAND lowdown -s -T man -o btop.1 ${CMAKE_CURRENT_SOURCE_DIR}/manpage.md
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/manpage.md
|
||||
VERBATIM
|
||||
)
|
||||
add_custom_target(generate_manpage ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/btop.1)
|
||||
# Install the man page
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/btop.1" DESTINATION "share/man/man1")
|
||||
else()
|
||||
message(STATUS "Command 'lowdown' not found: skipping generating man page btop.1")
|
||||
endif()
|
||||
|
||||
install(TARGETS btop RUNTIME)
|
||||
install(FILES "btop.desktop" DESTINATION "share/applications")
|
||||
install(FILES "Img/icon.png" DESTINATION "share/icons/hicolor/48x48/apps" RENAME "btop.png")
|
||||
install(FILES "Img/icon.svg" DESTINATION "share/icons/hicolor/scalable/apps" RENAME "btop.svg")
|
||||
install(DIRECTORY "themes" DESTINATION "share/btop")
|
||||
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
# Contributor Covenant 3.0
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We pledge to make our community welcoming, safe, and equitable for all.
|
||||
|
||||
We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant.
|
||||
|
||||
|
||||
## Encouraged Behaviors
|
||||
|
||||
While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language.
|
||||
|
||||
With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including:
|
||||
|
||||
1. Respecting the **purpose of our community**, our activities, and our ways of gathering.
|
||||
2. Engaging **kindly and honestly** with others.
|
||||
3. Respecting **different viewpoints** and experiences.
|
||||
4. **Taking responsibility** for our actions and contributions.
|
||||
5. Gracefully giving and accepting **constructive feedback**.
|
||||
6. Committing to **repairing harm** when it occurs.
|
||||
7. Behaving in other ways that promote and sustain the **well-being of our community**.
|
||||
|
||||
|
||||
## Restricted Behaviors
|
||||
|
||||
We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct.
|
||||
|
||||
1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop.
|
||||
2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people.
|
||||
3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits.
|
||||
4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community.
|
||||
5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission.
|
||||
6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.
|
||||
7. Behaving in other ways that **threaten the well-being** of our community.
|
||||
|
||||
### Other Restrictions
|
||||
|
||||
1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions.
|
||||
2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.
|
||||
3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community.
|
||||
4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors.
|
||||
|
||||
|
||||
## Reporting an Issue
|
||||
|
||||
Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm.
|
||||
|
||||
When an incident does occur, it is important to report it promptly. To report a possible violation, **[NOTE: describe your means of reporting here.]**
|
||||
|
||||
Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution.
|
||||
|
||||
|
||||
## Addressing and Repairing Harm
|
||||
|
||||
**[NOTE: The remedies and repairs outlined below are suggestions based on best practices in code of conduct enforcement. If your community has its own established enforcement process, be sure to edit this section to describe your own policies.]**
|
||||
|
||||
If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped.
|
||||
|
||||
1) Warning
|
||||
1) Event: A violation involving a single incident or series of incidents.
|
||||
2) Consequence: A private, written warning from the Community Moderators.
|
||||
3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations.
|
||||
2) Temporarily Limited Activities
|
||||
1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation.
|
||||
2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members.
|
||||
3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over.
|
||||
3) Temporary Suspension
|
||||
1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation.
|
||||
2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions.
|
||||
3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted.
|
||||
4) Permanent Ban
|
||||
1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member.
|
||||
2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior.
|
||||
3) Repair: There is no possible repair in cases of this severity.
|
||||
|
||||
This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community.
|
||||
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/).
|
||||
|
||||
Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
For answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion).
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
# Contributing guidelines
|
||||
|
||||
## When submitting pull requests
|
||||
|
||||
* Explain your thinking in why a change or addition is needed.
|
||||
* Is it a requested change or feature?
|
||||
* If not, open a feature request to get feedback before making a pull request.
|
||||
|
||||
* Split up multiple unrelated changes in multiple pull requests.
|
||||
|
||||
* If it's a fix for a unreported bug, make a bug report and link the pull request.
|
||||
|
||||
* Purely cosmetic changes won't be accepted without a very good explanation of its value.
|
||||
|
||||
* Submissions where the majority of the code is AI generated must be marked with [AI generated].
|
||||
|
||||
* "Vibe coded" PR's where it seems like the author doesn't understand the generated code will be dismissed.
|
||||
|
||||
## Formatting
|
||||
|
||||
### Follow the current syntax design
|
||||
|
||||
* Indent type: Tabs
|
||||
|
||||
* Tab size: 4
|
||||
|
||||
* Alternative operators `and`, `or` and `not`.
|
||||
|
||||
* Opening curly braces `{` at the end of the same line as the statement/condition.
|
||||
|
||||
## General guidelines
|
||||
|
||||
* Don't force a programming style. Use object oriented, functional, data oriented, etc., where it's suitable.
|
||||
|
||||
* Use [RAII](https://en.cppreference.com/w/cpp/language/raii).
|
||||
|
||||
* Make use of the standard algorithms library, watch [C++ Seasoning](https://www.youtube.com/watch?v=W2tWOdzgXHA) and [105 STL Algorithms](https://www.youtube.com/watch?v=bFSnXNIsK4A) for inspiration.
|
||||
|
||||
* Use the included `fmt` library for string formatting, see issue [#535](https://github.com/aristocratos/btop/issues/535) for more info and examples.
|
||||
|
||||
* Do not add includes if the same functionality can be achieved using the already included libraries.
|
||||
|
||||
* Use descriptive names for variables.
|
||||
|
||||
* Use comments if not very obvious what your code is doing.
|
||||
|
||||
* Add comments as labels for what's currently happening in bigger sections of code for better readability.
|
||||
|
||||
* Avoid writing to disk.
|
||||
|
||||
* If using the logger functions, be sensible, only call it if something of importance has changed.
|
||||
|
||||
* Benchmark your code and look for alternatives if they cause a noticeable negative impact.
|
||||
|
||||
For questions open a new discussion thread or send a mail to jakob@qvantnet.com
|
||||
|
||||
For proposing changes to this document create a [new issue](https://github.com/aristocratos/btop/issues/new/choose).
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="90"
|
||||
height="90"
|
||||
version="1.1"
|
||||
id="svg70"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs26">
|
||||
<pattern
|
||||
xlink:href="#gray-stripes"
|
||||
id="pattern1888" />
|
||||
<pattern
|
||||
xlink:href="#red-stripes"
|
||||
id="pattern1870" />
|
||||
<pattern
|
||||
id="red-stripes"
|
||||
width="341"
|
||||
height="90"
|
||||
patternUnits="userSpaceOnUse">
|
||||
<rect
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#f00"
|
||||
id="rect2" />
|
||||
<rect
|
||||
y="16"
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#d70000"
|
||||
id="rect4" />
|
||||
<rect
|
||||
y="32"
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#af0000"
|
||||
id="rect6" />
|
||||
<rect
|
||||
y="48"
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#870000"
|
||||
id="rect8" />
|
||||
<rect
|
||||
y="64"
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#5f0000"
|
||||
id="rect10" />
|
||||
</pattern>
|
||||
<pattern
|
||||
id="gray-stripes"
|
||||
width="341"
|
||||
height="90"
|
||||
patternUnits="userSpaceOnUse">
|
||||
<rect
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#585858"
|
||||
id="rect13" />
|
||||
<rect
|
||||
y="16"
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#4e4e4e"
|
||||
id="rect15" />
|
||||
<rect
|
||||
y="32"
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#444"
|
||||
id="rect17" />
|
||||
<rect
|
||||
y="48"
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#3a3a3a"
|
||||
id="rect19" />
|
||||
<rect
|
||||
y="64"
|
||||
width="341"
|
||||
height="16"
|
||||
fill="#303030"
|
||||
id="rect21" />
|
||||
<rect
|
||||
y="80"
|
||||
width="341"
|
||||
height="10"
|
||||
fill="#262626"
|
||||
id="rect23" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<g
|
||||
id="g2074"
|
||||
transform="translate(18)">
|
||||
<path
|
||||
d="M 2,7 V 90 H 47 V 74 h 7 V 55 H 47 V 42 h 7 V 23 H 47 V 7 Z M 19,26 H 37 V 39 H 19 Z m 0,32 H 37 V 71 H 19 Z"
|
||||
id="path28"
|
||||
style="fill:#080808" />
|
||||
<path
|
||||
d="M 2,7 V 90 H 47 V 74 h 7 V 55 H 47 V 42 h 7 V 23 H 47 V 7 Z m 1,1 h 43 v 16 h 7 v 17 h -7 v 15 h 7 V 73 H 46 V 89 H 3 Z M 18,25 H 38 V 40 H 18 Z m 1,1 V 39 H 37 V 26 Z M 18,57 H 38 V 72 H 18 Z m 1,1 V 71 H 37 V 58 Z M 4,9 V 88 H 45 V 72 h 7 V 57 H 45 V 40 h 7 V 25 H 45 V 9 Z m 1,1 h 39 v 16 h 7 v 13 h -7 v 19 h 7 V 71 H 44 V 87 H 5 Z M 16,23 H 40 V 42 H 16 Z m 1,1 V 41 H 39 V 24 Z M 16,55 H 40 V 74 H 16 Z m 1,1 V 73 H 39 V 56 Z"
|
||||
id="path42"
|
||||
style="fill:url(#pattern1888)" />
|
||||
<path
|
||||
d="M 0,0 V 80 H 42 V 64 h 7 V 48 H 42 V 32 h 7 V 16 H 42 V 0 Z M 14,16 H 35 V 32 H 14 Z m 0,32 H 35 V 64 H 14 Z"
|
||||
id="path56"
|
||||
style="fill:url(#pattern1870)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="341" height="90" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="red-stripes" width="341" height="90" patternUnits="userSpaceOnUse">
|
||||
<rect width="341" height="16" fill="#f00"/>
|
||||
<rect y="16" width="341" height="16" fill="#d70000"/>
|
||||
<rect y="32" width="341" height="16" fill="#af0000"/>
|
||||
<rect y="48" width="341" height="16" fill="#870000"/>
|
||||
<rect y="64" width="341" height="16" fill="#5f0000"/>
|
||||
</pattern>
|
||||
<pattern id="gray-stripes" width="341" height="90" patternUnits="userSpaceOnUse">
|
||||
<rect width="341" height="16" fill="#585858"/>
|
||||
<rect y="16" width="341" height="16" fill="#4e4e4e"/>
|
||||
<rect y="32" width="341" height="16" fill="#444"/>
|
||||
<rect y="48" width="341" height="16" fill="#3a3a3a"/>
|
||||
<rect y="64" width="341" height="16" fill="#303030"/>
|
||||
<rect y="80" width="341" height="10" fill="#262626"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<g fill="#080808">
|
||||
<path d="m2,7v83h45v-16h7v-19h-7v-13h7v-19h-7v-16h-45zm17,19h18v13h-18v-13zm0,32h18v13h-18v-13z"/>
|
||||
<path d="m58,7v19h21v64h17v-64h21v-19h-59z"/>
|
||||
<path d="m128,7v16h-7v51h7v16h45v-16h7v-51h-7v-16h-45zm10,19h25v45h-25v-45z"/>
|
||||
<path d="m184,7v83h17v-32h28v-16h7v-19h-7v-16h-45zm17,19h18v13h-18v-13z"/>
|
||||
<path d="m261,23v16h-14v19h14v16h17v-16h14v-19h-14v-16h-17z"/>
|
||||
<path d="m310,23v16h-14v19h14v16h17v-16h14v-19h-14v-16h-17z"/>
|
||||
</g>
|
||||
<g fill="url(#gray-stripes)">
|
||||
<path d="m2,7v83h45v-16h7v-19h-7v-13h7v-19h-7v-16h-45zm1,1h43v16h7v17h-7v15h7v17h-7v16h-43v-81zm15,17h20v15h-20v-15zm1,1v13h18v-13h-18zm-1,31h20v15h-20v-15zm1,1v13h18v-13h-18zm-15-49v79h41v-16h7v-15h-7v-17h7v-15h-7v-16h-41zm1,1h39v16h7v13h-7v19h7v13h-7v16h-39v-77zm11,13h24v19h-24v-19zm1,1v17h22v-17h-22zm-1,31h24v19h-24v-19zm1,1v17h22v-17h-22z"/>
|
||||
<path d="m58,7v19h21v64h17v-64h21v-19h-59zm1,1h57v17h-21v64h-15v-64h-21v-17zm1,1v15h21v64h13v-64h21v-15h-55zm1,1h53v13h-21v64h-11v-64h-21v-13z"/>
|
||||
<path d="m128,7v16h-7v51h7v16h45v-16h7v-51h-7v-16h-45zm1,1h43v16h7v49h-7v16h-43v-16h-7v-49h7v-16zm9,18v45h25v-45h-25zm-1-1h27v47h-27v-47zm-7-16v16h-7v47h7v16h41v-16h7v-47h-7v-16h-41zm1,1h39v16h7v45h-7v16h-39v-16h-7v-45h7v-16zm5,14v49h29v-49h-29zm-1-1h31v51h-31v-51z"/>
|
||||
<path d="m184,7v83h17v-32h28v-16h7v-19h-7v-16h-45zm1,1h43v16h7v17h-7v16h-28v32h-15v-81zm16,18v13h18v-13h-18zm-1-1h20v15h-20v-15zm-14-16v79h13v-32h28v-16h7v-15h-7v-16h-41zm1,1h39v16h7v13h-7v16h-28v32h-11v-77zm12,14v17h22v-17h-22zm-1-1h24v19h-24v-19z"/>
|
||||
<path d="m261,23v16h-14v19h14v16h17v-16h14v-19h-14v-16h-17zm1,1h15v16h14v17h-14v16h-15v-16h-14v-17h14v-16zm1,1v16h-14v15h14v16h13v-16h14v-15h-14v-16h-13zm1,1h11v16h14v13h-14v16h-11v-16h-14v-13h14v-16z"/>
|
||||
<path d="m310,23v16h-14v19h14v16h17v-16h14v-19h-14v-16h-17zm1,1h15v16h14v17h-14v16h-15v-16h-14v-17h14v-16zm1,1v16h-14v15h14v16h13v-16h14v-15h-14v-16h-13zm1,1h11v16h14v13h-14v16h-11v-16h-14v-13h14v-16z"/>
|
||||
</g>
|
||||
<g fill="url(#red-stripes)">
|
||||
<path d="m0,0v80h42v-16h7v-16h-7v-16h7v-16h-7v-16h-42zm14,16h21v16h-21v-16zm0,32h21v16h-21v-16z"/>
|
||||
<path d="m56,0v16h21v64h14v-64h21v-16h-56z"/>
|
||||
<path d="m126,0v16h-7v48h7v16h42v-16h7v-48h-7v-16h-42zm7,16h28v48h-28v-48z"/>
|
||||
<path d="m182,0v80h14v-32h28v-16h7v-16h-7v-16h-42zm14,16h21v16h-21v-16z"/>
|
||||
<path d="m259,16v16h-14v16h14v16h14v-16h14v-16h-14v-16h-14z"/>
|
||||
<path d="m308,16v16h-14v16h14v16h14v-16h14v-16h-14v-16h-14z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,16 @@
|
|||
[Desktop Entry]
|
||||
Type=Application
|
||||
Version=1.0
|
||||
Name=btop++
|
||||
GenericName=System Monitor
|
||||
GenericName[it]=Monitor di sistema
|
||||
GenericName[zh_TW]=系統監視器
|
||||
Comment=Resource monitor that shows usage and stats for processor, memory, disks, network and processes
|
||||
Comment[it]=Monitoraggio delle risorse: mostra utilizzo e statistiche per CPU, dischi, rete e processi
|
||||
Comment[zh_TW]=顯示處理器、主記憶體、磁碟、網路與進程的使用與統計數據的資源監視器應用程式
|
||||
Icon=btop
|
||||
Exec=btop
|
||||
Terminal=true
|
||||
Categories=System;Monitor;ConsoleOnly;
|
||||
Keywords=system;process;task
|
||||
Keywords[zh_TW]=系統;進程;處理程序;任務
|
||||
23
libs/external/chat-vault/monitoring/grafana/monitor-tui/cmake/Finddevstat.cmake
vendored
Normal file
23
libs/external/chat-vault/monitoring/grafana/monitor-tui/cmake/Finddevstat.cmake
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Find devstat, the Device Statistics Library
|
||||
#
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
|
||||
find_path(devstat_INCLUDE_DIR NAMES devstat.h)
|
||||
find_library(devstat_LIBRARY NAMES devstat)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(devstat REQUIRED_VARS devstat_LIBRARY devstat_INCLUDE_DIR)
|
||||
|
||||
if(devstat_FOUND AND NOT TARGET devstat::devstat)
|
||||
add_library(devstat::devstat UNKNOWN IMPORTED)
|
||||
set_target_properties(devstat::devstat PROPERTIES
|
||||
IMPORTED_LOCATION "${devstat_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${devstat_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(devstat_INCLUDE_DIR devstat_LIBRARY)
|
||||
endif()
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Find libelf, the ELF Access Library
|
||||
#
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
|
||||
find_path(elf_INCLUDE_DIR NAMES libelf.h)
|
||||
find_library(elf_LIBRARY NAMES elf)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(elf REQUIRED_VARS elf_LIBRARY elf_INCLUDE_DIR)
|
||||
|
||||
if(elf_FOUND AND NOT TARGET elf::elf)
|
||||
add_library(elf::elf UNKNOWN IMPORTED)
|
||||
set_target_properties(elf::elf PROPERTIES
|
||||
IMPORTED_LOCATION "${elf_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${elf_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(elf_INCLUDE_DIR elf_LIBRARY)
|
||||
endif()
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Find libkvm, the Kernel Data Access Library
|
||||
#
|
||||
|
||||
if(BSD)
|
||||
find_path(kvm_INCLUDE_DIR NAMES kvm.h)
|
||||
find_library(kvm_LIBRARY NAMES kvm)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(kvm REQUIRED_VARS kvm_LIBRARY kvm_INCLUDE_DIR)
|
||||
|
||||
if(kvm_FOUND AND NOT TARGET kvm::kvm)
|
||||
add_library(kvm::kvm UNKNOWN IMPORTED)
|
||||
set_target_properties(kvm::kvm PROPERTIES
|
||||
IMPORTED_LOCATION "${kvm_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${kvm_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(kvm_INCLUDE_DIR kvm_LIBRARY)
|
||||
endif()
|
||||
|
||||
23
libs/external/chat-vault/monitoring/grafana/monitor-tui/cmake/Findproplib.cmake
vendored
Normal file
23
libs/external/chat-vault/monitoring/grafana/monitor-tui/cmake/Findproplib.cmake
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Find proplib – property container object library
|
||||
#
|
||||
|
||||
if(BSD)
|
||||
find_path(proplib_INCLUDE_DIR NAMES prop/proplib.h)
|
||||
find_library(proplib_LIBRARY NAMES libprop prop)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(proplib REQUIRED_VARS proplib_LIBRARY proplib_INCLUDE_DIR)
|
||||
|
||||
if(proplib_FOUND AND NOT TARGET proplib::proplib)
|
||||
add_library(proplib::proplib UNKNOWN IMPORTED)
|
||||
set_target_properties(proplib::proplib PROPERTIES
|
||||
IMPORTED_LOCATION "${proplib_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${proplib_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(proplib_INCLUDE_DIR proplib_LIBRARY)
|
||||
endif()
|
||||
|
||||
27
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/LICENSE.rst
vendored
Normal file
27
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/LICENSE.rst
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--- Optional exception to the license ---
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into a machine-executable object form of such
|
||||
source code, you may redistribute such embedded portions in such object form
|
||||
without including the above copyright and permission notices.
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
// Formatting library for C++ - dynamic argument lists
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_ARGS_H_
|
||||
#define FMT_ARGS_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <functional> // std::reference_wrapper
|
||||
# include <memory> // std::unique_ptr
|
||||
# include <vector>
|
||||
#endif
|
||||
|
||||
#include "format.h" // std_string_view
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename T> struct is_reference_wrapper : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||
|
||||
template <typename T> auto unwrap(const T& v) -> const T& { return v; }
|
||||
template <typename T>
|
||||
auto unwrap(const std::reference_wrapper<T>& v) -> const T& {
|
||||
return static_cast<const T&>(v);
|
||||
}
|
||||
|
||||
// node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC
|
||||
// 2022 (v17.10.0).
|
||||
//
|
||||
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
|
||||
// templates it doesn't complain about inability to deduce single translation
|
||||
// unit for placing vtable. So node is made a fake template.
|
||||
template <typename = void> struct node {
|
||||
virtual ~node() = default;
|
||||
std::unique_ptr<node<>> next;
|
||||
};
|
||||
|
||||
class dynamic_arg_list {
|
||||
template <typename T> struct typed_node : node<> {
|
||||
T value;
|
||||
|
||||
template <typename Arg>
|
||||
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
|
||||
: value(arg.data(), arg.size()) {}
|
||||
};
|
||||
|
||||
std::unique_ptr<node<>> head_;
|
||||
|
||||
public:
|
||||
template <typename T, typename Arg> auto push(const Arg& arg) -> const T& {
|
||||
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
|
||||
auto& value = new_node->value;
|
||||
new_node->next = std::move(head_);
|
||||
head_ = std::move(new_node);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* A dynamic list of formatting arguments with storage.
|
||||
*
|
||||
* It can be implicitly converted into `fmt::basic_format_args` for passing
|
||||
* into type-erased formatting functions such as `fmt::vformat`.
|
||||
*/
|
||||
FMT_EXPORT template <typename Context> class dynamic_format_arg_store {
|
||||
private:
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
template <typename T> struct need_copy {
|
||||
static constexpr detail::type mapped_type =
|
||||
detail::mapped_type_constant<T, char_type>::value;
|
||||
|
||||
enum {
|
||||
value = !(detail::is_reference_wrapper<T>::value ||
|
||||
std::is_same<T, basic_string_view<char_type>>::value ||
|
||||
std::is_same<T, detail::std_string_view<char_type>>::value ||
|
||||
(mapped_type != detail::type::cstring_type &&
|
||||
mapped_type != detail::type::string_type &&
|
||||
mapped_type != detail::type::custom_type))
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using stored_t = conditional_t<
|
||||
std::is_convertible<T, std::basic_string<char_type>>::value &&
|
||||
!detail::is_reference_wrapper<T>::value,
|
||||
std::basic_string<char_type>, T>;
|
||||
|
||||
// Storage of basic_format_arg must be contiguous.
|
||||
std::vector<basic_format_arg<Context>> data_;
|
||||
std::vector<detail::named_arg_info<char_type>> named_info_;
|
||||
|
||||
// Storage of arguments not fitting into basic_format_arg must grow
|
||||
// without relocation because items in data_ refer to it.
|
||||
detail::dynamic_arg_list dynamic_args_;
|
||||
|
||||
friend class basic_format_args<Context>;
|
||||
|
||||
auto data() const -> const basic_format_arg<Context>* {
|
||||
return named_info_.empty() ? data_.data() : data_.data() + 1;
|
||||
}
|
||||
|
||||
template <typename T> void emplace_arg(const T& arg) {
|
||||
data_.emplace_back(arg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
|
||||
if (named_info_.empty())
|
||||
data_.insert(data_.begin(), basic_format_arg<Context>(nullptr, 0));
|
||||
data_.emplace_back(detail::unwrap(arg.value));
|
||||
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
|
||||
data->pop_back();
|
||||
};
|
||||
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
|
||||
guard{&data_, pop_one};
|
||||
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
|
||||
data_[0] = {named_info_.data(), named_info_.size()};
|
||||
guard.release();
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr dynamic_format_arg_store() = default;
|
||||
|
||||
operator basic_format_args<Context>() const {
|
||||
return basic_format_args<Context>(data(), static_cast<int>(data_.size()),
|
||||
!named_info_.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an argument into the dynamic store for later passing to a formatting
|
||||
* function.
|
||||
*
|
||||
* Note that custom types and string types (but not string views) are copied
|
||||
* into the store dynamically allocating memory if necessary.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
* store.push_back(42);
|
||||
* store.push_back("abc");
|
||||
* store.push_back(1.5f);
|
||||
* std::string result = fmt::vformat("{} and {} and {}", store);
|
||||
*/
|
||||
template <typename T> void push_back(const T& arg) {
|
||||
if (detail::const_check(need_copy<T>::value))
|
||||
emplace_arg(dynamic_args_.push<stored_t<T>>(arg));
|
||||
else
|
||||
emplace_arg(detail::unwrap(arg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a reference to the argument into the dynamic store for later passing
|
||||
* to a formatting function.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
* char band[] = "Rolling Stones";
|
||||
* store.push_back(std::cref(band));
|
||||
* band[9] = 'c'; // Changing str affects the output.
|
||||
* std::string result = fmt::vformat("{}", store);
|
||||
* // result == "Rolling Scones"
|
||||
*/
|
||||
template <typename T> void push_back(std::reference_wrapper<T> arg) {
|
||||
static_assert(
|
||||
need_copy<T>::value,
|
||||
"objects of built-in types and string views are always copied");
|
||||
emplace_arg(arg.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds named argument into the dynamic store for later passing to a
|
||||
* formatting function. `std::reference_wrapper` is supported to avoid
|
||||
* copying of the argument. The name is always copied into the store.
|
||||
*/
|
||||
template <typename T>
|
||||
void push_back(const detail::named_arg<char_type, T>& arg) {
|
||||
const char_type* arg_name =
|
||||
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
|
||||
if (detail::const_check(need_copy<T>::value)) {
|
||||
emplace_arg(
|
||||
fmt::arg(arg_name, dynamic_args_.push<stored_t<T>>(arg.value)));
|
||||
} else {
|
||||
emplace_arg(fmt::arg(arg_name, arg.value));
|
||||
}
|
||||
}
|
||||
|
||||
/// Erase all elements from the store.
|
||||
void clear() {
|
||||
data_.clear();
|
||||
named_info_.clear();
|
||||
dynamic_args_ = {};
|
||||
}
|
||||
|
||||
/// Reserves space to store at least `new_cap` arguments including
|
||||
/// `new_cap_named` named arguments.
|
||||
void reserve(size_t new_cap, size_t new_cap_named) {
|
||||
FMT_ASSERT(new_cap >= new_cap_named,
|
||||
"set of arguments includes set of named arguments");
|
||||
data_.reserve(new_cap);
|
||||
named_info_.reserve(new_cap_named);
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the store.
|
||||
auto size() const noexcept -> size_t { return data_.size(); }
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_ARGS_H_
|
||||
2994
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/base.h
vendored
Normal file
2994
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/base.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2241
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/chrono.h
vendored
Normal file
2241
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/chrono.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
637
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/color.h
vendored
Normal file
637
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/color.h
vendored
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
// Formatting library for C++ - color support
|
||||
//
|
||||
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_COLOR_H_
|
||||
#define FMT_COLOR_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
enum class color : uint32_t {
|
||||
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||
aqua = 0x00FFFF, // rgb(0,255,255)
|
||||
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
||||
azure = 0xF0FFFF, // rgb(240,255,255)
|
||||
beige = 0xF5F5DC, // rgb(245,245,220)
|
||||
bisque = 0xFFE4C4, // rgb(255,228,196)
|
||||
black = 0x000000, // rgb(0,0,0)
|
||||
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
||||
blue = 0x0000FF, // rgb(0,0,255)
|
||||
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
||||
brown = 0xA52A2A, // rgb(165,42,42)
|
||||
burly_wood = 0xDEB887, // rgb(222,184,135)
|
||||
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
||||
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
||||
chocolate = 0xD2691E, // rgb(210,105,30)
|
||||
coral = 0xFF7F50, // rgb(255,127,80)
|
||||
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
||||
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
||||
crimson = 0xDC143C, // rgb(220,20,60)
|
||||
cyan = 0x00FFFF, // rgb(0,255,255)
|
||||
dark_blue = 0x00008B, // rgb(0,0,139)
|
||||
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
||||
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
||||
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
||||
dark_green = 0x006400, // rgb(0,100,0)
|
||||
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
||||
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
||||
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
||||
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
||||
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
||||
dark_red = 0x8B0000, // rgb(139,0,0)
|
||||
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
||||
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
||||
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
||||
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
||||
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
||||
dark_violet = 0x9400D3, // rgb(148,0,211)
|
||||
deep_pink = 0xFF1493, // rgb(255,20,147)
|
||||
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
||||
dim_gray = 0x696969, // rgb(105,105,105)
|
||||
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
||||
fire_brick = 0xB22222, // rgb(178,34,34)
|
||||
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
||||
forest_green = 0x228B22, // rgb(34,139,34)
|
||||
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
||||
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
||||
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
||||
gold = 0xFFD700, // rgb(255,215,0)
|
||||
golden_rod = 0xDAA520, // rgb(218,165,32)
|
||||
gray = 0x808080, // rgb(128,128,128)
|
||||
green = 0x008000, // rgb(0,128,0)
|
||||
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
||||
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
||||
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
||||
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
||||
indigo = 0x4B0082, // rgb(75,0,130)
|
||||
ivory = 0xFFFFF0, // rgb(255,255,240)
|
||||
khaki = 0xF0E68C, // rgb(240,230,140)
|
||||
lavender = 0xE6E6FA, // rgb(230,230,250)
|
||||
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
||||
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
||||
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
||||
light_blue = 0xADD8E6, // rgb(173,216,230)
|
||||
light_coral = 0xF08080, // rgb(240,128,128)
|
||||
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
||||
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
||||
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
||||
light_green = 0x90EE90, // rgb(144,238,144)
|
||||
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
||||
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
||||
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
||||
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
||||
light_slate_gray = 0x778899, // rgb(119,136,153)
|
||||
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
||||
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
||||
lime = 0x00FF00, // rgb(0,255,0)
|
||||
lime_green = 0x32CD32, // rgb(50,205,50)
|
||||
linen = 0xFAF0E6, // rgb(250,240,230)
|
||||
magenta = 0xFF00FF, // rgb(255,0,255)
|
||||
maroon = 0x800000, // rgb(128,0,0)
|
||||
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
||||
medium_blue = 0x0000CD, // rgb(0,0,205)
|
||||
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
||||
medium_purple = 0x9370DB, // rgb(147,112,219)
|
||||
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
||||
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
||||
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
||||
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
||||
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
||||
midnight_blue = 0x191970, // rgb(25,25,112)
|
||||
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
||||
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
||||
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
||||
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
||||
navy = 0x000080, // rgb(0,0,128)
|
||||
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
||||
olive = 0x808000, // rgb(128,128,0)
|
||||
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
||||
orange = 0xFFA500, // rgb(255,165,0)
|
||||
orange_red = 0xFF4500, // rgb(255,69,0)
|
||||
orchid = 0xDA70D6, // rgb(218,112,214)
|
||||
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
||||
pale_green = 0x98FB98, // rgb(152,251,152)
|
||||
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
||||
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
||||
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
||||
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
||||
peru = 0xCD853F, // rgb(205,133,63)
|
||||
pink = 0xFFC0CB, // rgb(255,192,203)
|
||||
plum = 0xDDA0DD, // rgb(221,160,221)
|
||||
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
||||
purple = 0x800080, // rgb(128,0,128)
|
||||
rebecca_purple = 0x663399, // rgb(102,51,153)
|
||||
red = 0xFF0000, // rgb(255,0,0)
|
||||
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
||||
royal_blue = 0x4169E1, // rgb(65,105,225)
|
||||
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
||||
salmon = 0xFA8072, // rgb(250,128,114)
|
||||
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
||||
sea_green = 0x2E8B57, // rgb(46,139,87)
|
||||
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
||||
sienna = 0xA0522D, // rgb(160,82,45)
|
||||
silver = 0xC0C0C0, // rgb(192,192,192)
|
||||
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
||||
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
||||
slate_gray = 0x708090, // rgb(112,128,144)
|
||||
snow = 0xFFFAFA, // rgb(255,250,250)
|
||||
spring_green = 0x00FF7F, // rgb(0,255,127)
|
||||
steel_blue = 0x4682B4, // rgb(70,130,180)
|
||||
tan = 0xD2B48C, // rgb(210,180,140)
|
||||
teal = 0x008080, // rgb(0,128,128)
|
||||
thistle = 0xD8BFD8, // rgb(216,191,216)
|
||||
tomato = 0xFF6347, // rgb(255,99,71)
|
||||
turquoise = 0x40E0D0, // rgb(64,224,208)
|
||||
violet = 0xEE82EE, // rgb(238,130,238)
|
||||
wheat = 0xF5DEB3, // rgb(245,222,179)
|
||||
white = 0xFFFFFF, // rgb(255,255,255)
|
||||
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
||||
}; // enum class color
|
||||
|
||||
enum class terminal_color : uint8_t {
|
||||
black = 30,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
blue,
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
bright_black = 90,
|
||||
bright_red,
|
||||
bright_green,
|
||||
bright_yellow,
|
||||
bright_blue,
|
||||
bright_magenta,
|
||||
bright_cyan,
|
||||
bright_white
|
||||
};
|
||||
|
||||
enum class emphasis : uint8_t {
|
||||
bold = 1,
|
||||
faint = 1 << 1,
|
||||
italic = 1 << 2,
|
||||
underline = 1 << 3,
|
||||
blink = 1 << 4,
|
||||
reverse = 1 << 5,
|
||||
conceal = 1 << 6,
|
||||
strikethrough = 1 << 7,
|
||||
};
|
||||
|
||||
// rgb is a struct for red, green and blue colors.
|
||||
// Using the name "rgb" makes some editors show the color in a tooltip.
|
||||
struct rgb {
|
||||
constexpr rgb() : r(0), g(0), b(0) {}
|
||||
constexpr rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
|
||||
constexpr rgb(uint32_t hex)
|
||||
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
|
||||
constexpr rgb(color hex)
|
||||
: r((uint32_t(hex) >> 16) & 0xFF),
|
||||
g((uint32_t(hex) >> 8) & 0xFF),
|
||||
b(uint32_t(hex) & 0xFF) {}
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// A bit-packed variant of an RGB color, a terminal color, or unset color.
|
||||
// see text_style for the bit-packing scheme.
|
||||
struct color_type {
|
||||
constexpr color_type() noexcept = default;
|
||||
constexpr color_type(color rgb_color) noexcept
|
||||
: value_(static_cast<uint32_t>(rgb_color) | (1 << 24)) {}
|
||||
constexpr color_type(rgb rgb_color) noexcept
|
||||
: color_type(static_cast<color>(
|
||||
(static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b)) {}
|
||||
constexpr color_type(terminal_color term_color) noexcept
|
||||
: value_(static_cast<uint32_t>(term_color) | (3 << 24)) {}
|
||||
|
||||
constexpr auto is_terminal_color() const noexcept -> bool {
|
||||
return (value_ & (1 << 25)) != 0;
|
||||
}
|
||||
|
||||
constexpr auto value() const noexcept -> uint32_t {
|
||||
return value_ & 0xFFFFFF;
|
||||
}
|
||||
|
||||
constexpr color_type(uint32_t value) noexcept : value_(value) {}
|
||||
|
||||
uint32_t value_ = 0;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// A text style consisting of foreground and background colors and emphasis.
|
||||
class text_style {
|
||||
// The information is packed as follows:
|
||||
// ┌──┐
|
||||
// │ 0│─┐
|
||||
// │..│ ├── foreground color value
|
||||
// │23│─┘
|
||||
// ├──┤
|
||||
// │24│─┬── discriminator for the above value. 00 if unset, 01 if it's
|
||||
// │25│─┘ an RGB color, or 11 if it's a terminal color (10 is unused)
|
||||
// ├──┤
|
||||
// │26│──── overflow bit, always zero (see below)
|
||||
// ├──┤
|
||||
// │27│─┐
|
||||
// │..│ │
|
||||
// │50│ │
|
||||
// ├──┤ │
|
||||
// │51│ ├── background color (same format as the foreground color)
|
||||
// │52│ │
|
||||
// ├──┤ │
|
||||
// │53│─┘
|
||||
// ├──┤
|
||||
// │54│─┐
|
||||
// │..│ ├── emphases
|
||||
// │61│─┘
|
||||
// ├──┤
|
||||
// │62│─┬── unused
|
||||
// │63│─┘
|
||||
// └──┘
|
||||
// The overflow bits are there to make operator|= efficient.
|
||||
// When ORing, we must throw if, for either the foreground or background,
|
||||
// one style specifies a terminal color and the other specifies any color
|
||||
// (terminal or RGB); in other words, if one discriminator is 11 and the
|
||||
// other is 11 or 01.
|
||||
//
|
||||
// We do that check by adding the styles. Consider what adding does to each
|
||||
// possible pair of discriminators:
|
||||
// 00 + 00 = 000
|
||||
// 01 + 00 = 001
|
||||
// 11 + 00 = 011
|
||||
// 01 + 01 = 010
|
||||
// 11 + 01 = 100 (!!)
|
||||
// 11 + 11 = 110 (!!)
|
||||
// In the last two cases, the ones we want to catch, the third bit——the
|
||||
// overflow bit——is set. Bingo.
|
||||
//
|
||||
// We must take into account the possible carry bit from the bits
|
||||
// before the discriminator. The only potentially problematic case is
|
||||
// 11 + 00 = 011 (a carry bit would make it 100, not good!), but a carry
|
||||
// bit is impossible in that case, because 00 (unset color) means the
|
||||
// 24 bits that precede the discriminator are all zero.
|
||||
//
|
||||
// This test can be applied to both colors simultaneously.
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
|
||||
: style_(static_cast<uint64_t>(em) << 54) {}
|
||||
|
||||
FMT_CONSTEXPR auto operator|=(text_style rhs) -> text_style& {
|
||||
if (((style_ + rhs.style_) & ((1ULL << 26) | (1ULL << 53))) != 0)
|
||||
report_error("can't OR a terminal color");
|
||||
style_ |= rhs.style_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR auto operator|(text_style lhs, text_style rhs)
|
||||
-> text_style {
|
||||
return lhs |= rhs;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto operator==(text_style rhs) const noexcept -> bool {
|
||||
return style_ == rhs.style_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto operator!=(text_style rhs) const noexcept -> bool {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto has_foreground() const noexcept -> bool {
|
||||
return (style_ & (1 << 24)) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR auto has_background() const noexcept -> bool {
|
||||
return (style_ & (1ULL << 51)) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool {
|
||||
return (style_ >> 54) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type {
|
||||
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||
return style_ & 0x3FFFFFF;
|
||||
}
|
||||
FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type {
|
||||
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||
return (style_ >> 27) & 0x3FFFFFF;
|
||||
}
|
||||
FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis {
|
||||
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||
return static_cast<emphasis>(style_ >> 54);
|
||||
}
|
||||
|
||||
private:
|
||||
FMT_CONSTEXPR text_style(uint64_t style) noexcept : style_(style) {}
|
||||
|
||||
friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept
|
||||
-> text_style;
|
||||
|
||||
friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept
|
||||
-> text_style;
|
||||
|
||||
uint64_t style_ = 0;
|
||||
};
|
||||
|
||||
/// Creates a text style from the foreground (text) color.
|
||||
FMT_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept
|
||||
-> text_style {
|
||||
return foreground.value_;
|
||||
}
|
||||
|
||||
/// Creates a text style from the background color.
|
||||
FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept
|
||||
-> text_style {
|
||||
return static_cast<uint64_t>(background.value_) << 27;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept
|
||||
-> text_style {
|
||||
return text_style(lhs) | rhs;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Char> struct ansi_color_escape {
|
||||
FMT_CONSTEXPR ansi_color_escape(color_type text_color,
|
||||
const char* esc) noexcept {
|
||||
// If we have a terminal color, we need to output another escape code
|
||||
// sequence.
|
||||
if (text_color.is_terminal_color()) {
|
||||
bool is_background = esc == string_view("\x1b[48;2;");
|
||||
uint32_t value = text_color.value();
|
||||
// Background ASCII codes are the same as the foreground ones but with
|
||||
// 10 more.
|
||||
if (is_background) value += 10u;
|
||||
|
||||
buffer[size++] = static_cast<Char>('\x1b');
|
||||
buffer[size++] = static_cast<Char>('[');
|
||||
|
||||
if (value >= 100u) {
|
||||
buffer[size++] = static_cast<Char>('1');
|
||||
value %= 100u;
|
||||
}
|
||||
buffer[size++] = static_cast<Char>('0' + value / 10u);
|
||||
buffer[size++] = static_cast<Char>('0' + value % 10u);
|
||||
|
||||
buffer[size++] = static_cast<Char>('m');
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
buffer[i] = static_cast<Char>(esc[i]);
|
||||
}
|
||||
rgb color(text_color.value());
|
||||
to_esc(color.r, buffer + 7, ';');
|
||||
to_esc(color.g, buffer + 11, ';');
|
||||
to_esc(color.b, buffer + 15, 'm');
|
||||
size = 19;
|
||||
}
|
||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
|
||||
uint8_t em_codes[num_emphases] = {};
|
||||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
||||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
||||
if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3;
|
||||
if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4;
|
||||
if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5;
|
||||
if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7;
|
||||
if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
|
||||
if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
|
||||
|
||||
buffer[size++] = static_cast<Char>('\x1b');
|
||||
buffer[size++] = static_cast<Char>('[');
|
||||
|
||||
for (size_t i = 0; i < num_emphases; ++i) {
|
||||
if (!em_codes[i]) continue;
|
||||
buffer[size++] = static_cast<Char>('0' + em_codes[i]);
|
||||
buffer[size++] = static_cast<Char>(';');
|
||||
}
|
||||
|
||||
buffer[size - 1] = static_cast<Char>('m');
|
||||
}
|
||||
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
|
||||
|
||||
FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; }
|
||||
FMT_CONSTEXPR auto end() const noexcept -> const Char* {
|
||||
return buffer + size;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t num_emphases = 8;
|
||||
Char buffer[7u + 4u * num_emphases];
|
||||
size_t size = 0;
|
||||
|
||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||
char delimiter) noexcept {
|
||||
out[0] = static_cast<Char>('0' + c / 100);
|
||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||
out[2] = static_cast<Char>('0' + c % 10);
|
||||
out[3] = static_cast<Char>(delimiter);
|
||||
}
|
||||
static FMT_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept
|
||||
-> bool {
|
||||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR auto make_foreground_color(color_type foreground) noexcept
|
||||
-> ansi_color_escape<Char> {
|
||||
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR auto make_background_color(color_type background) noexcept
|
||||
-> ansi_color_escape<Char> {
|
||||
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept
|
||||
-> ansi_color_escape<Char> {
|
||||
return ansi_color_escape<Char>(em);
|
||||
}
|
||||
|
||||
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
buffer.append(reset_color.begin(), reset_color.end());
|
||||
}
|
||||
|
||||
template <typename T> struct styled_arg : view {
|
||||
const T& value;
|
||||
text_style style;
|
||||
styled_arg(const T& v, text_style s) : value(v), style(s) {}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
void vformat_to(buffer<Char>& buf, text_style ts, basic_string_view<Char> fmt,
|
||||
basic_format_args<buffered_context<Char>> args) {
|
||||
if (ts.has_emphasis()) {
|
||||
auto emphasis = make_emphasis<Char>(ts.get_emphasis());
|
||||
buf.append(emphasis.begin(), emphasis.end());
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
auto foreground = make_foreground_color<Char>(ts.get_foreground());
|
||||
buf.append(foreground.begin(), foreground.end());
|
||||
}
|
||||
if (ts.has_background()) {
|
||||
auto background = make_background_color<Char>(ts.get_background());
|
||||
buf.append(background.begin(), background.end());
|
||||
}
|
||||
vformat_to(buf, fmt, args);
|
||||
if (ts != text_style()) reset_color<Char>(buf);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline void vprint(FILE* f, text_style ts, string_view fmt, format_args args) {
|
||||
auto buf = memory_buffer();
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
print(f, FMT_STRING("{}"), string_view(buf.begin(), buf.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string and prints it to the specified file stream using ANSI
|
||||
* escape sequences to specify text formatting.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
* "Elapsed time: {0:.2f} seconds", 1.23);
|
||||
*/
|
||||
template <typename... T>
|
||||
void print(FILE* f, text_style ts, format_string<T...> fmt, T&&... args) {
|
||||
vprint(f, ts, fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string and prints it to stdout using ANSI escape sequences to
|
||||
* specify text formatting.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
* "Elapsed time: {0:.2f} seconds", 1.23);
|
||||
*/
|
||||
template <typename... T>
|
||||
void print(text_style ts, format_string<T...> fmt, T&&... args) {
|
||||
return print(stdout, ts, fmt, std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
inline auto vformat(text_style ts, string_view fmt, format_args args)
|
||||
-> std::string {
|
||||
auto buf = memory_buffer();
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
return fmt::to_string(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats arguments and returns the result as a string using ANSI escape
|
||||
* sequences to specify text formatting.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* ```
|
||||
* #include <fmt/color.h>
|
||||
* std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
* "The answer is {}", 42);
|
||||
* ```
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto format(text_style ts, format_string<T...> fmt, T&&... args)
|
||||
-> std::string {
|
||||
return fmt::vformat(ts, fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
/// Formats a string with the given text_style and writes the output to `out`.
|
||||
template <typename OutputIt,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
|
||||
auto vformat_to(OutputIt out, text_style ts, string_view fmt, format_args args)
|
||||
-> OutputIt {
|
||||
auto&& buf = detail::get_buffer<char>(out);
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
return detail::get_iterator(buf, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats arguments with the given text style, writes the result to the output
|
||||
* iterator `out` and returns the iterator past the end of the output range.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* std::vector<char> out;
|
||||
* fmt::format_to(std::back_inserter(out),
|
||||
* fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
|
||||
*/
|
||||
template <typename OutputIt, typename... T,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
|
||||
inline auto format_to(OutputIt out, text_style ts, format_string<T...> fmt,
|
||||
T&&... args) -> OutputIt {
|
||||
return vformat_to(out, ts, fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
const auto& ts = arg.style;
|
||||
auto out = ctx.out();
|
||||
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||
out = detail::copy<Char>(emphasis.begin(), emphasis.end(), out);
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
has_style = true;
|
||||
auto foreground =
|
||||
detail::make_foreground_color<Char>(ts.get_foreground());
|
||||
out = detail::copy<Char>(foreground.begin(), foreground.end(), out);
|
||||
}
|
||||
if (ts.has_background()) {
|
||||
has_style = true;
|
||||
auto background =
|
||||
detail::make_background_color<Char>(ts.get_background());
|
||||
out = detail::copy<Char>(background.begin(), background.end(), out);
|
||||
}
|
||||
out = formatter<T, Char>::format(arg.value, ctx);
|
||||
if (has_style) {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
out = detail::copy<Char>(reset_color.begin(), reset_color.end(), out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an argument that will be formatted using ANSI escape sequences,
|
||||
* to be used in a formatting function.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print("Elapsed time: {0:.2f} seconds",
|
||||
* fmt::styled(1.23, fmt::fg(fmt::color::green) |
|
||||
* fmt::bg(fmt::color::blue)));
|
||||
*/
|
||||
template <typename T>
|
||||
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
|
||||
-> detail::styled_arg<remove_cvref_t<T>> {
|
||||
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COLOR_H_
|
||||
585
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/compile.h
vendored
Normal file
585
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/compile.h
vendored
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
// Formatting library for C++ - experimental format string compilation
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_COMPILE_H_
|
||||
#define FMT_COMPILE_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <iterator> // std::back_inserter
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
// A compile-time string which is compiled into fast formatting code.
|
||||
FMT_EXPORT class compiled_string {};
|
||||
|
||||
template <typename S>
|
||||
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
||||
|
||||
/**
|
||||
* Converts a string literal `s` into a format string that will be parsed at
|
||||
* compile time and converted into efficient formatting code. Requires C++17
|
||||
* `constexpr if` compiler support.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* // Converts 42 into std::string using the most efficient method and no
|
||||
* // runtime format string processing.
|
||||
* std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
||||
*/
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string)
|
||||
#else
|
||||
# define FMT_COMPILE(s) FMT_STRING(s)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts a string literal into a format string that will be parsed at
|
||||
* compile time and converted into efficient formatting code. Requires support
|
||||
* for class types in constant template parameters (a C++20 feature).
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* // Converts 42 into std::string using the most efficient method and no
|
||||
* // runtime format string processing.
|
||||
* using namespace fmt::literals;
|
||||
* std::string s = fmt::format("{}"_cf, 42);
|
||||
*/
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
inline namespace literals {
|
||||
template <detail::fixed_string Str> constexpr auto operator""_cf() {
|
||||
return FMT_COMPILE(Str.data);
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename... Tail>
|
||||
constexpr auto first(const T& value, const Tail&...) -> const T& {
|
||||
return value;
|
||||
}
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
template <typename... T> struct type_list {};
|
||||
|
||||
// Returns a reference to the argument at index N from [first, rest...].
|
||||
template <int N, typename T, typename... Args>
|
||||
constexpr auto get([[maybe_unused]] const T& first,
|
||||
[[maybe_unused]] const Args&... rest) -> const auto& {
|
||||
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
||||
if constexpr (N == 0)
|
||||
return first;
|
||||
else
|
||||
return detail::get<N - 1>(rest...);
|
||||
}
|
||||
|
||||
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
template <int N, typename T, typename... Args, typename Char>
|
||||
constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
||||
if constexpr (is_static_named_arg<T>()) {
|
||||
if (name == T::name) return N;
|
||||
}
|
||||
if constexpr (sizeof...(Args) > 0)
|
||||
return get_arg_index_by_name<N + 1, Args...>(name);
|
||||
(void)name; // Workaround an MSVC bug about "unused" parameter.
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
|
||||
template <typename... Args, typename Char>
|
||||
FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
||||
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
if constexpr (sizeof...(Args) > 0)
|
||||
return get_arg_index_by_name<0, Args...>(name);
|
||||
# endif
|
||||
(void)name;
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename Char, typename... Args>
|
||||
constexpr auto get_arg_index_by_name(basic_string_view<Char> name,
|
||||
type_list<Args...>) -> int {
|
||||
return get_arg_index_by_name<Args...>(name);
|
||||
}
|
||||
|
||||
template <int N, typename> struct get_type_impl;
|
||||
|
||||
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
||||
using type =
|
||||
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
|
||||
};
|
||||
|
||||
template <int N, typename T>
|
||||
using get_type = typename get_type_impl<N, T>::type;
|
||||
|
||||
template <typename T> struct is_compiled_format : std::false_type {};
|
||||
|
||||
template <typename Char> struct text {
|
||||
basic_string_view<Char> data;
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&...) const -> OutputIt {
|
||||
return write<Char>(out, data);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<text<Char>> : std::true_type {};
|
||||
|
||||
template <typename Char>
|
||||
constexpr auto make_text(basic_string_view<Char> s, size_t pos, size_t size)
|
||||
-> text<Char> {
|
||||
return {{&s[pos], size}};
|
||||
}
|
||||
|
||||
template <typename Char> struct code_unit {
|
||||
Char value;
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&...) const -> OutputIt {
|
||||
*out++ = value;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
// This ensures that the argument type is convertible to `const T&`.
|
||||
template <typename T, int N, typename... Args>
|
||||
constexpr auto get_arg_checked(const Args&... args) -> const T& {
|
||||
const auto& arg = detail::get<N>(args...);
|
||||
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
|
||||
return arg.value;
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<code_unit<Char>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument N.
|
||||
template <typename Char, typename V, int N> struct field {
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&... args) const -> OutputIt {
|
||||
const V& arg = get_arg_checked<V, N>(args...);
|
||||
if constexpr (std::is_convertible<V, basic_string_view<Char>>::value) {
|
||||
auto s = basic_string_view<Char>(arg);
|
||||
return copy<Char>(s.begin(), s.end(), out);
|
||||
} else {
|
||||
return write<Char>(out, arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename T, int N>
|
||||
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument with name.
|
||||
template <typename Char> struct runtime_named_field {
|
||||
using char_type = Char;
|
||||
basic_string_view<Char> name;
|
||||
|
||||
template <typename OutputIt, typename T>
|
||||
constexpr static auto try_format_argument(
|
||||
OutputIt& out,
|
||||
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
|
||||
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) -> bool {
|
||||
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
|
||||
if (arg_name == arg.name) {
|
||||
out = write<Char>(out, arg.value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&... args) const -> OutputIt {
|
||||
bool found = (try_format_argument(out, name, args) || ...);
|
||||
if (!found) {
|
||||
FMT_THROW(format_error("argument with specified name is not found"));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument N and has format specifiers.
|
||||
template <typename Char, typename V, int N> struct spec_field {
|
||||
using char_type = Char;
|
||||
formatter<V, Char> fmt;
|
||||
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr FMT_INLINE auto format(OutputIt out, const T&... args) const
|
||||
-> OutputIt {
|
||||
const auto& vargs =
|
||||
fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
|
||||
basic_format_context<OutputIt, Char> ctx(out, vargs);
|
||||
return fmt.format(get_arg_checked<V, N>(args...), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename T, int N>
|
||||
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
|
||||
|
||||
template <typename L, typename R> struct concat {
|
||||
L lhs;
|
||||
R rhs;
|
||||
using char_type = typename L::char_type;
|
||||
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&... args) const -> OutputIt {
|
||||
out = lhs.format(out, args...);
|
||||
return rhs.format(out, args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct is_compiled_format<concat<L, R>> : std::true_type {};
|
||||
|
||||
template <typename L, typename R>
|
||||
constexpr auto make_concat(L lhs, R rhs) -> concat<L, R> {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
struct unknown_format {};
|
||||
|
||||
template <typename Char>
|
||||
constexpr auto parse_text(basic_string_view<Char> str, size_t pos) -> size_t {
|
||||
for (size_t size = str.size(); pos != size; ++pos) {
|
||||
if (str[pos] == '{' || str[pos] == '}') break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
template <typename Args, size_t POS, int ID, typename S>
|
||||
constexpr auto compile_format_string(S fmt);
|
||||
|
||||
template <typename Args, size_t POS, int ID, typename T, typename S>
|
||||
constexpr auto parse_tail(T head, S fmt) {
|
||||
if constexpr (POS != basic_string_view<typename S::char_type>(fmt).size()) {
|
||||
constexpr auto tail = compile_format_string<Args, POS, ID>(fmt);
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
|
||||
unknown_format>())
|
||||
return tail;
|
||||
else
|
||||
return make_concat(head, tail);
|
||||
} else {
|
||||
return head;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Char> struct parse_specs_result {
|
||||
formatter<T, Char> fmt;
|
||||
size_t end;
|
||||
int next_arg_id;
|
||||
};
|
||||
|
||||
enum { manual_indexing_id = -1 };
|
||||
|
||||
template <typename T, typename Char>
|
||||
constexpr auto parse_specs(basic_string_view<Char> str, size_t pos,
|
||||
int next_arg_id) -> parse_specs_result<T, Char> {
|
||||
str.remove_prefix(pos);
|
||||
auto ctx =
|
||||
compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id);
|
||||
auto f = formatter<T, Char>();
|
||||
auto end = f.parse(ctx);
|
||||
return {f, pos + fmt::detail::to_unsigned(end - str.data()),
|
||||
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
|
||||
}
|
||||
|
||||
template <typename Char> struct arg_id_handler {
|
||||
arg_id_kind kind;
|
||||
arg_ref<Char> arg_id;
|
||||
|
||||
constexpr auto on_auto() -> int {
|
||||
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
||||
return 0;
|
||||
}
|
||||
constexpr auto on_index(int id) -> int {
|
||||
kind = arg_id_kind::index;
|
||||
arg_id = arg_ref<Char>(id);
|
||||
return 0;
|
||||
}
|
||||
constexpr auto on_name(basic_string_view<Char> id) -> int {
|
||||
kind = arg_id_kind::name;
|
||||
arg_id = arg_ref<Char>(id);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char> struct parse_arg_id_result {
|
||||
arg_id_kind kind;
|
||||
arg_ref<Char> arg_id;
|
||||
const Char* arg_id_end;
|
||||
};
|
||||
|
||||
template <int ID, typename Char>
|
||||
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
|
||||
auto handler = arg_id_handler<Char>{arg_id_kind::none, arg_ref<Char>{}};
|
||||
auto arg_id_end = parse_arg_id(begin, end, handler);
|
||||
return parse_arg_id_result<Char>{handler.kind, handler.arg_id, arg_id_end};
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void> struct field_type {
|
||||
using type = remove_cvref_t<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
|
||||
using type = remove_cvref_t<decltype(T::value)>;
|
||||
};
|
||||
|
||||
template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
|
||||
typename S>
|
||||
constexpr auto parse_replacement_field_then_tail(S fmt) {
|
||||
using char_type = typename S::char_type;
|
||||
constexpr auto str = basic_string_view<char_type>(fmt);
|
||||
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
|
||||
if constexpr (c == '}') {
|
||||
return parse_tail<Args, END_POS + 1, NEXT_ID>(
|
||||
field<char_type, typename field_type<T>::type, ARG_INDEX>(), fmt);
|
||||
} else if constexpr (c != ':') {
|
||||
FMT_THROW(format_error("expected ':'"));
|
||||
} else {
|
||||
constexpr auto result = parse_specs<typename field_type<T>::type>(
|
||||
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
|
||||
if constexpr (result.end >= str.size() || str[result.end] != '}') {
|
||||
FMT_THROW(format_error("expected '}'"));
|
||||
return 0;
|
||||
} else {
|
||||
return parse_tail<Args, result.end + 1, result.next_arg_id>(
|
||||
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
|
||||
result.fmt},
|
||||
fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compiles a non-empty format string and returns the compiled representation
|
||||
// or unknown_format() on unrecognized input.
|
||||
template <typename Args, size_t POS, int ID, typename S>
|
||||
constexpr auto compile_format_string(S fmt) {
|
||||
using char_type = typename S::char_type;
|
||||
constexpr auto str = basic_string_view<char_type>(fmt);
|
||||
if constexpr (str[POS] == '{') {
|
||||
if constexpr (POS + 1 == str.size())
|
||||
FMT_THROW(format_error("unmatched '{' in format string"));
|
||||
if constexpr (str[POS + 1] == '{') {
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), fmt);
|
||||
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
|
||||
static_assert(ID != manual_indexing_id,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
constexpr auto next_id =
|
||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||
return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
|
||||
POS + 1, ID, next_id>(fmt);
|
||||
} else {
|
||||
constexpr auto arg_id_result =
|
||||
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
|
||||
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
|
||||
constexpr char_type c =
|
||||
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
|
||||
static_assert(c == '}' || c == ':', "missing '}' in format string");
|
||||
if constexpr (arg_id_result.kind == arg_id_kind::index) {
|
||||
static_assert(
|
||||
ID == manual_indexing_id || ID == 0,
|
||||
"cannot switch from automatic to manual argument indexing");
|
||||
constexpr auto arg_index = arg_id_result.arg_id.index;
|
||||
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
|
||||
Args, arg_id_end_pos,
|
||||
arg_index, manual_indexing_id>(
|
||||
fmt);
|
||||
} else if constexpr (arg_id_result.kind == arg_id_kind::name) {
|
||||
constexpr auto arg_index =
|
||||
get_arg_index_by_name(arg_id_result.arg_id.name, Args{});
|
||||
if constexpr (arg_index >= 0) {
|
||||
constexpr auto next_id =
|
||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||
return parse_replacement_field_then_tail<
|
||||
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
|
||||
arg_index, next_id>(fmt);
|
||||
} else if constexpr (c == '}') {
|
||||
return parse_tail<Args, arg_id_end_pos + 1, ID>(
|
||||
runtime_named_field<char_type>{arg_id_result.arg_id.name}, fmt);
|
||||
} else if constexpr (c == ':') {
|
||||
return unknown_format(); // no type info for specs parsing
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if constexpr (str[POS] == '}') {
|
||||
if constexpr (POS + 1 == str.size())
|
||||
FMT_THROW(format_error("unmatched '}' in format string"));
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), fmt);
|
||||
} else {
|
||||
constexpr auto end = parse_text(str, POS + 1);
|
||||
if constexpr (end - POS > 1) {
|
||||
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS), fmt);
|
||||
} else {
|
||||
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args, typename S,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
constexpr auto compile(S fmt) {
|
||||
constexpr auto str = basic_string_view<typename S::char_type>(fmt);
|
||||
if constexpr (str.size() == 0) {
|
||||
return detail::make_text(str, 0, 0);
|
||||
} else {
|
||||
constexpr auto result =
|
||||
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(fmt);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
} // namespace detail
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
|
||||
template <typename CompiledFormat, typename... T,
|
||||
typename Char = typename CompiledFormat::char_type,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
FMT_INLINE FMT_CONSTEXPR_STRING auto format(const CompiledFormat& cf,
|
||||
const T&... args)
|
||||
-> std::basic_string<Char> {
|
||||
auto s = std::basic_string<Char>();
|
||||
cf.format(std::back_inserter(s), args...);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename CompiledFormat, typename... T,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
constexpr FMT_INLINE auto format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const T&... args) -> OutputIt {
|
||||
return cf.format(out, args...);
|
||||
}
|
||||
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
FMT_INLINE FMT_CONSTEXPR_STRING auto format(const S&, T&&... args)
|
||||
-> std::basic_string<typename S::char_type> {
|
||||
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
||||
constexpr auto str = basic_string_view<typename S::char_type>(S());
|
||||
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
|
||||
const auto& first = detail::first(args...);
|
||||
if constexpr (detail::is_named_arg<
|
||||
remove_cvref_t<decltype(first)>>::value) {
|
||||
return fmt::to_string(first.value);
|
||||
} else {
|
||||
return fmt::to_string(first);
|
||||
}
|
||||
}
|
||||
}
|
||||
constexpr auto compiled = detail::compile<T...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return fmt::format(
|
||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<T>(args)...);
|
||||
} else {
|
||||
return fmt::format(compiled, std::forward<T>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
FMT_CONSTEXPR auto format_to(OutputIt out, const S&, T&&... args) -> OutputIt {
|
||||
constexpr auto compiled = detail::compile<T...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return fmt::format_to(
|
||||
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<T>(args)...);
|
||||
} else {
|
||||
return fmt::format_to(out, compiled, std::forward<T>(args)...);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
using traits = detail::fixed_buffer_traits;
|
||||
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
|
||||
fmt::format_to(std::back_inserter(buf), fmt, std::forward<T>(args)...);
|
||||
return {buf.out(), buf.count()};
|
||||
}
|
||||
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
FMT_CONSTEXPR20 auto formatted_size(const S& fmt, T&&... args) -> size_t {
|
||||
auto buf = detail::counting_buffer<>();
|
||||
fmt::format_to(appender(buf), fmt, std::forward<T>(args)...);
|
||||
return buf.count();
|
||||
}
|
||||
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
void print(std::FILE* f, const S& fmt, T&&... args) {
|
||||
auto buf = memory_buffer();
|
||||
fmt::format_to(appender(buf), fmt, std::forward<T>(args)...);
|
||||
detail::print(f, {buf.data(), buf.size()});
|
||||
}
|
||||
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
void print(const S& fmt, T&&... args) {
|
||||
print(stdout, fmt, std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
template <size_t N> class static_format_result {
|
||||
private:
|
||||
char data[N];
|
||||
|
||||
public:
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
explicit FMT_CONSTEXPR static_format_result(const S& fmt, T&&... args) {
|
||||
*fmt::format_to(data, fmt, std::forward<T>(args)...) = '\0';
|
||||
}
|
||||
|
||||
auto str() const -> fmt::string_view { return {data, N - 1}; }
|
||||
auto c_str() const -> const char* { return data; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats arguments according to the format string `fmt_str` and produces
|
||||
* a string of the exact required size at compile time. Both the format string
|
||||
* and the arguments must be compile-time expressions.
|
||||
*
|
||||
* The resulting string can be accessed as a C string via `c_str()` or as
|
||||
* a `fmt::string_view` via `str()`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* // Produces the static string "42" at compile time.
|
||||
* static constexpr auto result = FMT_STATIC_FORMAT("{}", 42);
|
||||
* const char* s = result.c_str();
|
||||
*/
|
||||
#define FMT_STATIC_FORMAT(fmt_str, ...) \
|
||||
fmt::static_format_result< \
|
||||
fmt::formatted_size(FMT_COMPILE(fmt_str), __VA_ARGS__) + 1>( \
|
||||
FMT_COMPILE(fmt_str), __VA_ARGS__)
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COMPILE_H_
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// This file is only provided for compatibility and may be removed in future
|
||||
// versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h
|
||||
// otherwise.
|
||||
|
||||
#include "format.h"
|
||||
1953
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/format-inl.h
vendored
Normal file
1953
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/format-inl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4383
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/format.h
vendored
Normal file
4383
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/format.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,428 @@
|
|||
// Formatting library for C++ - optional OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OS_H_
|
||||
#define FMT_OS_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <cerrno>
|
||||
# include <cstddef>
|
||||
# include <cstdio>
|
||||
# include <system_error> // std::system_error
|
||||
|
||||
# if FMT_HAS_INCLUDE(<xlocale.h>)
|
||||
# include <xlocale.h> // LC_NUMERIC_MASK on macOS
|
||||
# endif
|
||||
#endif // FMT_MODULE
|
||||
|
||||
#ifndef FMT_USE_FCNTL
|
||||
// UWP doesn't provide _pipe.
|
||||
# if FMT_HAS_INCLUDE("winapifamily.h")
|
||||
# include <winapifamily.h>
|
||||
# endif
|
||||
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||
defined(__linux__)) && \
|
||||
(!defined(WINAPI_FAMILY) || \
|
||||
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) && \
|
||||
!defined(__wasm__)
|
||||
# include <fcntl.h> // for O_RDONLY
|
||||
# define FMT_USE_FCNTL 1
|
||||
# else
|
||||
# define FMT_USE_FCNTL 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FMT_POSIX
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX(call) _##call
|
||||
# else
|
||||
# define FMT_POSIX(call) call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
||||
#ifdef FMT_SYSTEM
|
||||
# define FMT_HAS_SYSTEM
|
||||
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
||||
#else
|
||||
# define FMT_SYSTEM(call) ::call
|
||||
# ifdef _WIN32
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX_CALL(call) ::_##call
|
||||
# else
|
||||
# define FMT_POSIX_CALL(call) ::call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Retries the expression while it evaluates to error_result and errno
|
||||
// equals to EINTR.
|
||||
#ifndef _WIN32
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) \
|
||||
do { \
|
||||
(result) = (expression); \
|
||||
} while ((result) == (error_result) && errno == EINTR)
|
||||
#else
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
||||
#endif
|
||||
|
||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
/**
|
||||
* A reference to a null-terminated string. It can be constructed from a C
|
||||
* string or `std::string`.
|
||||
*
|
||||
* You can use one of the following type aliases for common character types:
|
||||
*
|
||||
* +---------------+-----------------------------+
|
||||
* | Type | Definition |
|
||||
* +===============+=============================+
|
||||
* | cstring_view | basic_cstring_view<char> |
|
||||
* +---------------+-----------------------------+
|
||||
* | wcstring_view | basic_cstring_view<wchar_t> |
|
||||
* +---------------+-----------------------------+
|
||||
*
|
||||
* This class is most useful as a parameter type for functions that wrap C APIs.
|
||||
*/
|
||||
template <typename Char> class basic_cstring_view {
|
||||
private:
|
||||
const Char* data_;
|
||||
|
||||
public:
|
||||
/// Constructs a string reference object from a C string.
|
||||
basic_cstring_view(const Char* s) : data_(s) {}
|
||||
|
||||
/// Constructs a string reference from an `std::string` object.
|
||||
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
|
||||
|
||||
/// Returns the pointer to a C string.
|
||||
auto c_str() const -> const Char* { return data_; }
|
||||
};
|
||||
|
||||
using cstring_view = basic_cstring_view<char>;
|
||||
using wcstring_view = basic_cstring_view<wchar_t>;
|
||||
|
||||
#ifdef _WIN32
|
||||
FMT_API const std::error_category& system_category() noexcept;
|
||||
|
||||
namespace detail {
|
||||
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
||||
const char* message) noexcept;
|
||||
}
|
||||
|
||||
FMT_API std::system_error vwindows_error(int error_code, string_view fmt,
|
||||
format_args args);
|
||||
|
||||
/**
|
||||
* Constructs a `std::system_error` object with the description of the form
|
||||
*
|
||||
* <message>: <system-message>
|
||||
*
|
||||
* where `<message>` is the formatted message and `<system-message>` is the
|
||||
* system message corresponding to the error code.
|
||||
* `error_code` is a Windows error code as given by `GetLastError`.
|
||||
* If `error_code` is not a valid error code such as -1, the system message
|
||||
* will look like "error -1".
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* // This throws a system_error with the description
|
||||
* // cannot open file 'madeup': The system cannot find the file
|
||||
* specified.
|
||||
* // or similar (system message may vary).
|
||||
* const char *filename = "madeup";
|
||||
* LPOFSTRUCT of = LPOFSTRUCT();
|
||||
* HFILE file = OpenFile(filename, &of, OF_READ);
|
||||
* if (file == HFILE_ERROR) {
|
||||
* throw fmt::windows_error(GetLastError(),
|
||||
* "cannot open file '{}'", filename);
|
||||
* }
|
||||
*/
|
||||
template <typename... T>
|
||||
auto windows_error(int error_code, string_view message, const T&... args)
|
||||
-> std::system_error {
|
||||
return vwindows_error(error_code, message, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
// Reports a Windows error without throwing an exception.
|
||||
// Can be used to report errors from destructors.
|
||||
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
|
||||
#else
|
||||
inline auto system_category() noexcept -> const std::error_category& {
|
||||
return std::system_category();
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// std::system is not available on some platforms such as iOS (#2248).
|
||||
#ifdef __OSX__
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
void say(const S& fmt, Args&&... args) {
|
||||
std::system(format("say \"{}\"", format(fmt, args...)).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
// A buffered file.
|
||||
class buffered_file {
|
||||
private:
|
||||
FILE* file_;
|
||||
|
||||
friend class file;
|
||||
|
||||
inline explicit buffered_file(FILE* f) : file_(f) {}
|
||||
|
||||
public:
|
||||
buffered_file(const buffered_file&) = delete;
|
||||
void operator=(const buffered_file&) = delete;
|
||||
|
||||
// Constructs a buffered_file object which doesn't represent any file.
|
||||
inline buffered_file() noexcept : file_(nullptr) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~buffered_file() noexcept;
|
||||
|
||||
public:
|
||||
inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
|
||||
inline auto operator=(buffered_file&& other) -> buffered_file& {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Opens a file.
|
||||
FMT_API buffered_file(cstring_view filename, cstring_view mode);
|
||||
|
||||
// Closes the file.
|
||||
FMT_API void close();
|
||||
|
||||
// Returns the pointer to a FILE object representing this file.
|
||||
inline auto get() const noexcept -> FILE* { return file_; }
|
||||
|
||||
FMT_API auto descriptor() const -> int;
|
||||
|
||||
template <typename... T>
|
||||
inline void print(string_view fmt, const T&... args) {
|
||||
fmt::vargs<T...> vargs = {{args...}};
|
||||
detail::is_locking<T...>() ? fmt::vprint_buffered(file_, fmt, vargs)
|
||||
: fmt::vprint(file_, fmt, vargs);
|
||||
}
|
||||
};
|
||||
|
||||
#if FMT_USE_FCNTL
|
||||
|
||||
// A file. Closed file is represented by a file object with descriptor -1.
|
||||
// Methods that are not declared with noexcept may throw
|
||||
// fmt::system_error in case of failure. Note that some errors such as
|
||||
// closing the file multiple times will cause a crash on Windows rather
|
||||
// than an exception. You can get standard behavior by overriding the
|
||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||
class FMT_API file {
|
||||
private:
|
||||
int fd_; // File descriptor.
|
||||
|
||||
// Constructs a file object with a given descriptor.
|
||||
explicit file(int fd) : fd_(fd) {}
|
||||
|
||||
friend struct pipe;
|
||||
|
||||
public:
|
||||
// Possible values for the oflag argument to the constructor.
|
||||
enum {
|
||||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
|
||||
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
|
||||
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
|
||||
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
|
||||
};
|
||||
|
||||
// Constructs a file object which doesn't represent any file.
|
||||
inline file() noexcept : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a file object representing this file.
|
||||
file(cstring_view path, int oflag);
|
||||
|
||||
public:
|
||||
file(const file&) = delete;
|
||||
void operator=(const file&) = delete;
|
||||
|
||||
inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
|
||||
|
||||
// Move assignment is not noexcept because close may throw.
|
||||
inline auto operator=(file&& other) -> file& {
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
~file() noexcept;
|
||||
|
||||
// Returns the file descriptor.
|
||||
inline auto descriptor() const noexcept -> int { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
|
||||
// Returns the file size. The size has signed type for consistency with
|
||||
// stat::st_size.
|
||||
auto size() const -> long long;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
auto read(void* buffer, size_t count) -> size_t;
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
auto write(const void* buffer, size_t count) -> size_t;
|
||||
|
||||
// Duplicates a file descriptor with the dup function and returns
|
||||
// the duplicate as a file object.
|
||||
static auto dup(int fd) -> file;
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd, std::error_code& ec) noexcept;
|
||||
|
||||
// Creates a buffered_file object associated with this file and detaches
|
||||
// this file object from the file.
|
||||
auto fdopen(const char* mode) -> buffered_file;
|
||||
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// Opens a file and constructs a file object representing this file by
|
||||
// wcstring_view filename. Windows only.
|
||||
static file open_windows_file(wcstring_view path, int oflag);
|
||||
# endif
|
||||
};
|
||||
|
||||
struct FMT_API pipe {
|
||||
file read_end;
|
||||
file write_end;
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
pipe();
|
||||
};
|
||||
|
||||
// Returns the memory page size.
|
||||
auto getpagesize() -> long;
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct buffer_size {
|
||||
constexpr buffer_size() = default;
|
||||
size_t value = 0;
|
||||
FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size {
|
||||
auto bs = buffer_size();
|
||||
bs.value = val;
|
||||
return bs;
|
||||
}
|
||||
};
|
||||
|
||||
struct ostream_params {
|
||||
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
|
||||
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
|
||||
|
||||
constexpr ostream_params() {}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
|
||||
oflag = new_oflag;
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, detail::buffer_size bs)
|
||||
: ostream_params(params...) {
|
||||
this->buffer_size = bs.value;
|
||||
}
|
||||
|
||||
// Intel has a bug that results in failure to deduce a constructor
|
||||
// for empty parameter packs.
|
||||
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
|
||||
ostream_params(int new_oflag) : oflag(new_oflag) {}
|
||||
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
|
||||
# endif
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size();
|
||||
|
||||
/// A fast buffered output stream for writing from a single thread. Writing from
|
||||
/// multiple threads without external synchronization may result in a data race.
|
||||
class FMT_API ostream : private detail::buffer<char> {
|
||||
private:
|
||||
file file_;
|
||||
|
||||
ostream(cstring_view path, const detail::ostream_params& params);
|
||||
|
||||
static void grow(buffer<char>& buf, size_t);
|
||||
|
||||
public:
|
||||
ostream(ostream&& other) noexcept;
|
||||
~ostream();
|
||||
|
||||
operator writer() {
|
||||
detail::buffer<char>& buf = *this;
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline void flush() {
|
||||
if (size() == 0) return;
|
||||
file_.write(data(), size() * sizeof(data()[0]));
|
||||
clear();
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
friend auto output_file(cstring_view path, T... params) -> ostream;
|
||||
|
||||
inline void close() {
|
||||
flush();
|
||||
file_.close();
|
||||
}
|
||||
|
||||
/// Formats `args` according to specifications in `fmt` and writes the
|
||||
/// output to the file.
|
||||
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
|
||||
vformat_to(appender(*this), fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens a file for writing. Supported parameters passed in `params`:
|
||||
*
|
||||
* - `<integer>`: Flags passed to [open](
|
||||
* https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html)
|
||||
* (`file::WRONLY | file::CREATE | file::TRUNC` by default)
|
||||
* - `buffer_size=<integer>`: Output buffer size
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* auto out = fmt::output_file("guide.txt");
|
||||
* out.print("Don't {}", "Panic");
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto output_file(cstring_view path, T... params) -> ostream {
|
||||
return {path, detail::ostream_params(params...)};
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OS_H_
|
||||
167
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/ostream.h
vendored
Normal file
167
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/ostream.h
vendored
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
// Formatting library for C++ - std::ostream support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OSTREAM_H_
|
||||
#define FMT_OSTREAM_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <fstream> // std::filebuf
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef __GLIBCXX__
|
||||
# include <ext/stdio_filebuf.h>
|
||||
# include <ext/stdio_sync_filebuf.h>
|
||||
# endif
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "chrono.h" // formatbuf
|
||||
|
||||
#ifdef _MSVC_STL_UPDATE
|
||||
# define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5
|
||||
# define FMT_MSVC_STL_UPDATE _MSVC_LANG
|
||||
#else
|
||||
# define FMT_MSVC_STL_UPDATE 0
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
// Generate a unique explicit instantiation in every translation unit using a
|
||||
// tag type in an anonymous namespace.
|
||||
namespace {
|
||||
struct file_access_tag {};
|
||||
} // namespace
|
||||
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
|
||||
class file_access {
|
||||
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
|
||||
};
|
||||
|
||||
#if FMT_MSVC_STL_UPDATE
|
||||
template class file_access<file_access_tag, std::filebuf,
|
||||
&std::filebuf::_Myfile>;
|
||||
auto get_file(std::filebuf&) -> FILE*;
|
||||
#endif
|
||||
|
||||
// Write the content of buf to os.
|
||||
// It is a separate function rather than a part of vprint to simplify testing.
|
||||
template <typename Char>
|
||||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||
const Char* buf_data = buf.data();
|
||||
using unsigned_streamsize = make_unsigned_t<std::streamsize>;
|
||||
unsigned_streamsize size = buf.size();
|
||||
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
|
||||
do {
|
||||
unsigned_streamsize n = size <= max_size ? size : max_size;
|
||||
os.write(buf_data, static_cast<std::streamsize>(n));
|
||||
buf_data += n;
|
||||
size -= n;
|
||||
} while (size != 0);
|
||||
}
|
||||
|
||||
template <typename T> struct streamed_view {
|
||||
const T& value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
template <typename Char>
|
||||
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
|
||||
void set_debug_format() = delete;
|
||||
|
||||
template <typename T, typename Context>
|
||||
auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) {
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer);
|
||||
auto&& output = std::basic_ostream<Char>(&formatbuf);
|
||||
output.imbue(std::locale::classic()); // The default is always unlocalized.
|
||||
output << value;
|
||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
return formatter<basic_string_view<Char>, Char>::format(
|
||||
{buffer.data(), buffer.size()}, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
using ostream_formatter = basic_ostream_formatter<char>;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<detail::streamed_view<T>, Char>
|
||||
: basic_ostream_formatter<Char> {
|
||||
template <typename Context>
|
||||
auto format(detail::streamed_view<T> view, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return basic_ostream_formatter<Char>::format(view.value, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a view that formats `value` via an ostream `operator<<`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print("Current thread id: {}\n",
|
||||
* fmt::streamed(std::this_thread::get_id()));
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr auto streamed(const T& value) -> detail::streamed_view<T> {
|
||||
return {value};
|
||||
}
|
||||
|
||||
inline void vprint(std::ostream& os, string_view fmt, format_args args) {
|
||||
auto buffer = memory_buffer();
|
||||
detail::vformat_to(buffer, fmt, args);
|
||||
FILE* f = nullptr;
|
||||
#if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI
|
||||
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
|
||||
f = detail::get_file(*buf);
|
||||
#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI
|
||||
auto* rdbuf = os.rdbuf();
|
||||
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
|
||||
f = sfbuf->file();
|
||||
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
|
||||
f = fbuf->file();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
if (f) {
|
||||
int fd = _fileno(f);
|
||||
if (_isatty(fd)) {
|
||||
os.flush();
|
||||
if (detail::write_console(fd, {buffer.data(), buffer.size()})) return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
detail::ignore_unused(f);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints formatted data to the stream `os`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print(cerr, "Don't {}!", "panic");
|
||||
*/
|
||||
FMT_EXPORT template <typename... T>
|
||||
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||
fmt::vargs<T...> vargs = {{args...}};
|
||||
if (detail::const_check(detail::use_utf8)) return vprint(os, fmt.str, vargs);
|
||||
auto buffer = memory_buffer();
|
||||
detail::vformat_to(buffer, fmt.str, vargs);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
FMT_EXPORT template <typename... T>
|
||||
void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||
fmt::print(os, FMT_STRING("{}\n"),
|
||||
fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OSTREAM_H_
|
||||
624
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/printf.h
vendored
Normal file
624
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/printf.h
vendored
Normal file
|
|
@ -0,0 +1,624 @@
|
|||
// Formatting library for C++ - legacy printf implementation
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_PRINTF_H_
|
||||
#define FMT_PRINTF_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <algorithm> // std::find
|
||||
# include <limits> // std::numeric_limits
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
template <typename Char> class basic_printf_context {
|
||||
private:
|
||||
basic_appender<Char> out_;
|
||||
basic_format_args<basic_printf_context> args_;
|
||||
|
||||
static_assert(std::is_same<Char, char>::value ||
|
||||
std::is_same<Char, wchar_t>::value,
|
||||
"Unsupported code unit type.");
|
||||
|
||||
public:
|
||||
using char_type = Char;
|
||||
enum { builtin_types = 1 };
|
||||
|
||||
/// Constructs a `printf_context` object. References to the arguments are
|
||||
/// stored in the context object so make sure they have appropriate lifetimes.
|
||||
basic_printf_context(basic_appender<Char> out,
|
||||
basic_format_args<basic_printf_context> args)
|
||||
: out_(out), args_(args) {}
|
||||
|
||||
auto out() -> basic_appender<Char> { return out_; }
|
||||
void advance_to(basic_appender<Char>) {}
|
||||
|
||||
auto locale() -> locale_ref { return {}; }
|
||||
|
||||
auto arg(int id) const -> basic_format_arg<basic_printf_context> {
|
||||
return args_.get(id);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Return the result via the out param to workaround gcc bug 77539.
|
||||
template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
|
||||
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
|
||||
for (out = first; out != last; ++out) {
|
||||
if (*out == value) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline auto find<false, char>(const char* first, const char* last, char value,
|
||||
const char*& out) -> bool {
|
||||
out =
|
||||
static_cast<const char*>(memchr(first, value, to_unsigned(last - first)));
|
||||
return out != nullptr;
|
||||
}
|
||||
|
||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||
// signed and unsigned integers.
|
||||
template <bool IS_SIGNED> struct int_checker {
|
||||
template <typename T> static auto fits_in_int(T value) -> bool {
|
||||
return value <= to_unsigned(max_value<int>());
|
||||
}
|
||||
inline static auto fits_in_int(bool) -> bool { return true; }
|
||||
};
|
||||
|
||||
template <> struct int_checker<true> {
|
||||
template <typename T> static auto fits_in_int(T value) -> bool {
|
||||
return value >= (std::numeric_limits<int>::min)() &&
|
||||
value <= max_value<int>();
|
||||
}
|
||||
inline static auto fits_in_int(int) -> bool { return true; }
|
||||
};
|
||||
|
||||
struct printf_precision_handler {
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
auto operator()(T value) -> int {
|
||||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||
report_error("number is too big");
|
||||
return max_of(static_cast<int>(value), 0);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
auto operator()(T) -> int {
|
||||
report_error("precision is not integer");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// An argument visitor that returns true iff arg is a zero integer.
|
||||
struct is_zero_int {
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
auto operator()(T value) -> bool {
|
||||
return value == 0;
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
auto operator()(T) -> bool {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
|
||||
|
||||
template <> struct make_unsigned_or_bool<bool> {
|
||||
using type = bool;
|
||||
};
|
||||
|
||||
template <typename T, typename Context> class arg_converter {
|
||||
private:
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
basic_format_arg<Context>& arg_;
|
||||
char_type type_;
|
||||
|
||||
public:
|
||||
arg_converter(basic_format_arg<Context>& arg, char_type type)
|
||||
: arg_(arg), type_(type) {}
|
||||
|
||||
void operator()(bool value) {
|
||||
if (type_ != 's') operator()<bool>(value);
|
||||
}
|
||||
|
||||
template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
|
||||
void operator()(U value) {
|
||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||
using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
|
||||
if (const_check(sizeof(target_type) <= sizeof(int))) {
|
||||
// Extra casts are used to silence warnings.
|
||||
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
|
||||
if (is_signed)
|
||||
arg_ = static_cast<int>(static_cast<target_type>(value));
|
||||
else
|
||||
arg_ = static_cast<unsigned>(static_cast<unsigned_type>(value));
|
||||
} else {
|
||||
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||
// std::printf("%lld", -42); // prints "4294967254"
|
||||
// but we don't have to do the same because it's a UB.
|
||||
if (is_signed)
|
||||
arg_ = static_cast<long long>(value);
|
||||
else
|
||||
arg_ = static_cast<typename make_unsigned_or_bool<U>::type>(value);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)>
|
||||
void operator()(U) {} // No conversion needed for non-integral types.
|
||||
};
|
||||
|
||||
// Converts an integer argument to T for printf, if T is an integral type.
|
||||
// If T is void, the argument is converted to corresponding signed or unsigned
|
||||
// type depending on the type specifier: 'd' and 'i' - signed, other -
|
||||
// unsigned).
|
||||
template <typename T, typename Context, typename Char>
|
||||
void convert_arg(basic_format_arg<Context>& arg, Char type) {
|
||||
arg.visit(arg_converter<T, Context>(arg, type));
|
||||
}
|
||||
|
||||
// Converts an integer argument to char for printf.
|
||||
template <typename Context> class char_converter {
|
||||
private:
|
||||
basic_format_arg<Context>& arg_;
|
||||
|
||||
public:
|
||||
explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
void operator()(T value) {
|
||||
arg_ = static_cast<typename Context::char_type>(value);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
void operator()(T) {} // No conversion needed for non-integral types.
|
||||
};
|
||||
|
||||
// An argument visitor that return a pointer to a C string if argument is a
|
||||
// string or null otherwise.
|
||||
template <typename Char> struct get_cstring {
|
||||
template <typename T> auto operator()(T) -> const Char* { return nullptr; }
|
||||
auto operator()(const Char* s) -> const Char* { return s; }
|
||||
};
|
||||
|
||||
// Checks if an argument is a valid printf width specifier and sets
|
||||
// left alignment if it is negative.
|
||||
class printf_width_handler {
|
||||
private:
|
||||
format_specs& specs_;
|
||||
|
||||
public:
|
||||
inline explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
auto operator()(T value) -> unsigned {
|
||||
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
||||
if (detail::is_negative(value)) {
|
||||
specs_.set_align(align::left);
|
||||
width = 0 - width;
|
||||
}
|
||||
unsigned int_max = to_unsigned(max_value<int>());
|
||||
if (width > int_max) report_error("number is too big");
|
||||
return static_cast<unsigned>(width);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
auto operator()(T) -> unsigned {
|
||||
report_error("width is not integer");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Workaround for a bug with the XL compiler when initializing
|
||||
// printf_arg_formatter's base class.
|
||||
template <typename Char>
|
||||
auto make_arg_formatter(basic_appender<Char> iter, format_specs& s)
|
||||
-> arg_formatter<Char> {
|
||||
return {iter, s, locale_ref()};
|
||||
}
|
||||
|
||||
// The `printf` argument formatter.
|
||||
template <typename Char>
|
||||
class printf_arg_formatter : public arg_formatter<Char> {
|
||||
private:
|
||||
using base = arg_formatter<Char>;
|
||||
using context_type = basic_printf_context<Char>;
|
||||
|
||||
context_type& context_;
|
||||
|
||||
void write_null_pointer(bool is_string = false) {
|
||||
auto s = this->specs;
|
||||
s.set_type(presentation_type::none);
|
||||
write_bytes<Char>(this->out, is_string ? "(null)" : "(nil)", s);
|
||||
}
|
||||
|
||||
template <typename T> void write(T value) {
|
||||
detail::write<Char>(this->out, value, this->specs, this->locale);
|
||||
}
|
||||
|
||||
public:
|
||||
printf_arg_formatter(basic_appender<Char> iter, format_specs& s,
|
||||
context_type& ctx)
|
||||
: base(make_arg_formatter(iter, s)), context_(ctx) {}
|
||||
|
||||
void operator()(monostate value) { write(value); }
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
|
||||
void operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and Char so use
|
||||
// std::is_same instead.
|
||||
if (!std::is_same<T, Char>::value) {
|
||||
write(value);
|
||||
return;
|
||||
}
|
||||
format_specs s = this->specs;
|
||||
if (s.type() != presentation_type::none &&
|
||||
s.type() != presentation_type::chr) {
|
||||
return (*this)(static_cast<int>(value));
|
||||
}
|
||||
s.set_sign(sign::none);
|
||||
s.clear_alt();
|
||||
s.set_fill(' '); // Ignore '0' flag for char types.
|
||||
// align::numeric needs to be overwritten here since the '0' flag is
|
||||
// ignored for non-numeric types
|
||||
if (s.align() == align::none || s.align() == align::numeric)
|
||||
s.set_align(align::right);
|
||||
detail::write<Char>(this->out, static_cast<Char>(value), s);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
||||
void operator()(T value) {
|
||||
write(value);
|
||||
}
|
||||
|
||||
void operator()(const char* value) {
|
||||
if (value)
|
||||
write(value);
|
||||
else
|
||||
write_null_pointer(this->specs.type() != presentation_type::pointer);
|
||||
}
|
||||
|
||||
void operator()(const wchar_t* value) {
|
||||
if (value)
|
||||
write(value);
|
||||
else
|
||||
write_null_pointer(this->specs.type() != presentation_type::pointer);
|
||||
}
|
||||
|
||||
void operator()(basic_string_view<Char> value) { write(value); }
|
||||
|
||||
void operator()(const void* value) {
|
||||
if (value)
|
||||
write(value);
|
||||
else
|
||||
write_null_pointer();
|
||||
}
|
||||
|
||||
void operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||
auto parse_ctx = parse_context<Char>({});
|
||||
handle.format(parse_ctx, context_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
void parse_flags(format_specs& specs, const Char*& it, const Char* end) {
|
||||
for (; it != end; ++it) {
|
||||
switch (*it) {
|
||||
case '-': specs.set_align(align::left); break;
|
||||
case '+': specs.set_sign(sign::plus); break;
|
||||
case '0': specs.set_fill('0'); break;
|
||||
case ' ':
|
||||
if (specs.sign() != sign::plus) specs.set_sign(sign::space);
|
||||
break;
|
||||
case '#': specs.set_alt(); break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char, typename GetArg>
|
||||
auto parse_header(const Char*& it, const Char* end, format_specs& specs,
|
||||
GetArg get_arg) -> int {
|
||||
int arg_index = -1;
|
||||
Char c = *it;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// Parse an argument index (if followed by '$') or a width possibly
|
||||
// preceded with '0' flag(s).
|
||||
int value = parse_nonnegative_int(it, end, -1);
|
||||
if (it != end && *it == '$') { // value is an argument index
|
||||
++it;
|
||||
arg_index = value != -1 ? value : max_value<int>();
|
||||
} else {
|
||||
if (c == '0') specs.set_fill('0');
|
||||
if (value != 0) {
|
||||
// Nonzero value means that we parsed width and don't need to
|
||||
// parse it or flags again, so return now.
|
||||
if (value == -1) report_error("number is too big");
|
||||
specs.width = value;
|
||||
return arg_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_flags(specs, it, end);
|
||||
// Parse width.
|
||||
if (it != end) {
|
||||
if (*it >= '0' && *it <= '9') {
|
||||
specs.width = parse_nonnegative_int(it, end, -1);
|
||||
if (specs.width == -1) report_error("number is too big");
|
||||
} else if (*it == '*') {
|
||||
++it;
|
||||
specs.width = static_cast<int>(
|
||||
get_arg(-1).visit(detail::printf_width_handler(specs)));
|
||||
}
|
||||
}
|
||||
return arg_index;
|
||||
}
|
||||
|
||||
inline auto parse_printf_presentation_type(char c, type t, bool& upper)
|
||||
-> presentation_type {
|
||||
using pt = presentation_type;
|
||||
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
|
||||
switch (c) {
|
||||
case 'd': return in(t, integral_set) ? pt::dec : pt::none;
|
||||
case 'o': return in(t, integral_set) ? pt::oct : pt::none;
|
||||
case 'X': upper = true; FMT_FALLTHROUGH;
|
||||
case 'x': return in(t, integral_set) ? pt::hex : pt::none;
|
||||
case 'E': upper = true; FMT_FALLTHROUGH;
|
||||
case 'e': return in(t, float_set) ? pt::exp : pt::none;
|
||||
case 'F': upper = true; FMT_FALLTHROUGH;
|
||||
case 'f': return in(t, float_set) ? pt::fixed : pt::none;
|
||||
case 'G': upper = true; FMT_FALLTHROUGH;
|
||||
case 'g': return in(t, float_set) ? pt::general : pt::none;
|
||||
case 'A': upper = true; FMT_FALLTHROUGH;
|
||||
case 'a': return in(t, float_set) ? pt::hexfloat : pt::none;
|
||||
case 'c': return in(t, integral_set) ? pt::chr : pt::none;
|
||||
case 's': return in(t, string_set | cstring_set) ? pt::string : pt::none;
|
||||
case 'p': return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
|
||||
default: return pt::none;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char, typename Context>
|
||||
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
basic_format_args<Context> args) {
|
||||
using iterator = basic_appender<Char>;
|
||||
auto out = iterator(buf);
|
||||
auto context = basic_printf_context<Char>(out, args);
|
||||
auto parse_ctx = parse_context<Char>(format);
|
||||
|
||||
// Returns the argument with specified index or, if arg_index is -1, the next
|
||||
// argument.
|
||||
auto get_arg = [&](int arg_index) {
|
||||
if (arg_index < 0)
|
||||
arg_index = parse_ctx.next_arg_id();
|
||||
else
|
||||
parse_ctx.check_arg_id(--arg_index);
|
||||
auto arg = context.arg(arg_index);
|
||||
if (!arg) report_error("argument not found");
|
||||
return arg;
|
||||
};
|
||||
|
||||
const Char* start = parse_ctx.begin();
|
||||
const Char* end = parse_ctx.end();
|
||||
auto it = start;
|
||||
while (it != end) {
|
||||
if (!find<false, Char>(it, end, '%', it)) {
|
||||
it = end; // find leaves it == nullptr if it doesn't find '%'.
|
||||
break;
|
||||
}
|
||||
Char c = *it++;
|
||||
if (it != end && *it == c) {
|
||||
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
|
||||
start = ++it;
|
||||
continue;
|
||||
}
|
||||
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
|
||||
|
||||
auto specs = format_specs();
|
||||
specs.set_align(align::right);
|
||||
|
||||
// Parse argument index, flags and width.
|
||||
int arg_index = parse_header(it, end, specs, get_arg);
|
||||
if (arg_index == 0) report_error("argument not found");
|
||||
|
||||
// Parse precision.
|
||||
if (it != end && *it == '.') {
|
||||
++it;
|
||||
c = it != end ? *it : 0;
|
||||
if ('0' <= c && c <= '9') {
|
||||
specs.precision = parse_nonnegative_int(it, end, 0);
|
||||
} else if (c == '*') {
|
||||
++it;
|
||||
specs.precision =
|
||||
static_cast<int>(get_arg(-1).visit(printf_precision_handler()));
|
||||
} else {
|
||||
specs.precision = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto arg = get_arg(arg_index);
|
||||
// For d, i, o, u, x, and X conversion specifiers, if a precision is
|
||||
// specified, the '0' flag is ignored
|
||||
if (specs.precision >= 0 && is_integral_type(arg.type())) {
|
||||
// Ignore '0' for non-numeric types or if '-' present.
|
||||
specs.set_fill(' ');
|
||||
}
|
||||
if (specs.precision >= 0 && arg.type() == type::cstring_type) {
|
||||
auto str = arg.visit(get_cstring<Char>());
|
||||
auto str_end = str + specs.precision;
|
||||
auto nul = std::find(str, str_end, Char());
|
||||
auto sv = basic_string_view<Char>(
|
||||
str, to_unsigned(nul != str_end ? nul - str : specs.precision));
|
||||
arg = sv;
|
||||
}
|
||||
if (specs.alt() && arg.visit(is_zero_int())) specs.clear_alt();
|
||||
if (specs.fill_unit<Char>() == '0') {
|
||||
if (is_arithmetic_type(arg.type()) && specs.align() != align::left) {
|
||||
specs.set_align(align::numeric);
|
||||
} else {
|
||||
// Ignore '0' flag for non-numeric types or if '-' flag is also present.
|
||||
specs.set_fill(' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Parse length and convert the argument to the required type.
|
||||
c = it != end ? *it++ : 0;
|
||||
Char t = it != end ? *it : 0;
|
||||
switch (c) {
|
||||
case 'h':
|
||||
if (t == 'h') {
|
||||
++it;
|
||||
t = it != end ? *it : 0;
|
||||
convert_arg<signed char>(arg, t);
|
||||
} else {
|
||||
convert_arg<short>(arg, t);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (t == 'l') {
|
||||
++it;
|
||||
t = it != end ? *it : 0;
|
||||
convert_arg<long long>(arg, t);
|
||||
} else {
|
||||
convert_arg<long>(arg, t);
|
||||
}
|
||||
break;
|
||||
case 'j': convert_arg<intmax_t>(arg, t); break;
|
||||
case 'z': convert_arg<size_t>(arg, t); break;
|
||||
case 't': convert_arg<std::ptrdiff_t>(arg, t); break;
|
||||
case 'L':
|
||||
// printf produces garbage when 'L' is omitted for long double, no
|
||||
// need to do the same.
|
||||
break;
|
||||
default: --it; convert_arg<void>(arg, c);
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (it == end) report_error("invalid format string");
|
||||
char type = static_cast<char>(*it++);
|
||||
if (is_integral_type(arg.type())) {
|
||||
// Normalize type.
|
||||
switch (type) {
|
||||
case 'i':
|
||||
case 'u': type = 'd'; break;
|
||||
case 'c':
|
||||
arg.visit(char_converter<basic_printf_context<Char>>(arg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool upper = false;
|
||||
specs.set_type(parse_printf_presentation_type(type, arg.type(), upper));
|
||||
if (specs.type() == presentation_type::none)
|
||||
report_error("invalid format specifier");
|
||||
if (upper) specs.set_upper();
|
||||
|
||||
start = it;
|
||||
|
||||
// Format argument.
|
||||
arg.visit(printf_arg_formatter<Char>(out, specs, context));
|
||||
}
|
||||
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
using printf_context = basic_printf_context<char>;
|
||||
using wprintf_context = basic_printf_context<wchar_t>;
|
||||
|
||||
using printf_args = basic_format_args<printf_context>;
|
||||
using wprintf_args = basic_format_args<wprintf_context>;
|
||||
|
||||
/// Constructs an `format_arg_store` object that contains references to
|
||||
/// arguments and can be implicitly converted to `printf_args`.
|
||||
template <typename Char = char, typename... T>
|
||||
inline auto make_printf_args(T&... args)
|
||||
-> decltype(fmt::make_format_args<basic_printf_context<Char>>(args...)) {
|
||||
return fmt::make_format_args<basic_printf_context<Char>>(args...);
|
||||
}
|
||||
|
||||
template <typename Char> struct vprintf_args {
|
||||
using type = basic_format_args<basic_printf_context<Char>>;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
inline auto vsprintf(basic_string_view<Char> fmt,
|
||||
typename vprintf_args<Char>::type args)
|
||||
-> std::basic_string<Char> {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vprintf(buf, fmt, args);
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats `args` according to specifications in `fmt` and returns the result
|
||||
* as as string.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* std::string message = fmt::sprintf("The answer is %d", 42);
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto sprintf(string_view fmt, const T&... args) -> std::string {
|
||||
return vsprintf(fmt, make_printf_args(args...));
|
||||
}
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED auto sprintf(basic_string_view<wchar_t> fmt, const T&... args)
|
||||
-> std::wstring {
|
||||
return vsprintf(fmt, make_printf_args<wchar_t>(args...));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
auto vfprintf(std::FILE* f, basic_string_view<Char> fmt,
|
||||
typename vprintf_args<Char>::type args) -> int {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vprintf(buf, fmt, args);
|
||||
size_t size = buf.size();
|
||||
return std::fwrite(buf.data(), sizeof(Char), size, f) < size
|
||||
? -1
|
||||
: static_cast<int>(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats `args` according to specifications in `fmt` and writes the output
|
||||
* to `f`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::fprintf(stderr, "Don't %s!", "panic");
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto fprintf(std::FILE* f, string_view fmt, const T&... args) -> int {
|
||||
return vfprintf(f, fmt, make_printf_args(args...));
|
||||
}
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED auto fprintf(std::FILE* f, basic_string_view<wchar_t> fmt,
|
||||
const T&... args) -> int {
|
||||
return vfprintf(f, fmt, make_printf_args<wchar_t>(args...));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats `args` according to specifications in `fmt` and writes the output
|
||||
* to `stdout`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto printf(string_view fmt, const T&... args) -> int {
|
||||
return vfprintf(stdout, fmt, make_printf_args(args...));
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_PRINTF_H_
|
||||
852
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/ranges.h
vendored
Normal file
852
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/ranges.h
vendored
Normal file
|
|
@ -0,0 +1,852 @@
|
|||
// Formatting library for C++ - range and tuple support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_RANGES_H_
|
||||
#define FMT_RANGES_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <initializer_list>
|
||||
# include <iterator>
|
||||
# include <tuple>
|
||||
# include <type_traits>
|
||||
# include <utility>
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
FMT_EXPORT
|
||||
enum class range_format { disabled, map, set, sequence, string, debug_string };
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T> class is_map {
|
||||
template <typename U> static auto check(U*) -> typename U::mapped_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename T> class is_set {
|
||||
template <typename U> static auto check(U*) -> typename U::key_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||
};
|
||||
|
||||
// C array overload
|
||||
template <typename T, size_t N>
|
||||
auto range_begin(const T (&arr)[N]) -> const T* {
|
||||
return arr;
|
||||
}
|
||||
template <typename T, size_t N> auto range_end(const T (&arr)[N]) -> const T* {
|
||||
return arr + N;
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_member_fn_begin_end_t : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()),
|
||||
decltype(std::declval<T>().end())>>
|
||||
: std::true_type {};
|
||||
|
||||
// Member function overloads.
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) {
|
||||
return static_cast<T&&>(rng).begin();
|
||||
}
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
|
||||
return static_cast<T&&>(rng).end();
|
||||
}
|
||||
|
||||
// ADL overloads. Only participate in overload resolution if member functions
|
||||
// are not found.
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng)
|
||||
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||
decltype(begin(static_cast<T&&>(rng)))> {
|
||||
return begin(static_cast<T&&>(rng));
|
||||
}
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||
decltype(end(static_cast<T&&>(rng)))> {
|
||||
return end(static_cast<T&&>(rng));
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_const_begin_end : std::false_type {};
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_mutable_begin_end : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_const_begin_end<
|
||||
T, void_t<decltype(*detail::range_begin(
|
||||
std::declval<const remove_cvref_t<T>&>())),
|
||||
decltype(detail::range_end(
|
||||
std::declval<const remove_cvref_t<T>&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_mutable_begin_end<
|
||||
T, void_t<decltype(*detail::range_begin(std::declval<T&>())),
|
||||
decltype(detail::range_end(std::declval<T&>())),
|
||||
// the extra int here is because older versions of MSVC don't
|
||||
// SFINAE properly unless there are distinct types
|
||||
int>> : std::true_type {};
|
||||
|
||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_range_<T, void>
|
||||
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
|
||||
has_mutable_begin_end<T>::value)> {};
|
||||
|
||||
// tuple_size and tuple_element check.
|
||||
template <typename T> class is_tuple_like_ {
|
||||
template <typename U, typename V = typename std::remove_cv<U>::type>
|
||||
static auto check(U* p) -> decltype(std::tuple_size<V>::value, 0);
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
// Check for integer_sequence
|
||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
|
||||
template <typename T, T... N>
|
||||
using integer_sequence = std::integer_sequence<T, N...>;
|
||||
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
|
||||
#else
|
||||
template <typename T, T... N> struct integer_sequence {
|
||||
using value_type = T;
|
||||
|
||||
static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); }
|
||||
};
|
||||
|
||||
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
|
||||
|
||||
template <typename T, size_t N, T... Ns>
|
||||
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
|
||||
template <typename T, T... Ns>
|
||||
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
|
||||
|
||||
template <size_t N>
|
||||
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
|
||||
|
||||
template <typename T, typename C, bool = is_tuple_like_<T>::value>
|
||||
class is_tuple_formattable_ {
|
||||
public:
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
|
||||
template <size_t... Is>
|
||||
static auto all_true(index_sequence<Is...>,
|
||||
integer_sequence<bool, (Is >= 0)...>) -> std::true_type;
|
||||
static auto all_true(...) -> std::false_type;
|
||||
|
||||
template <size_t... Is>
|
||||
static auto check(index_sequence<Is...>) -> decltype(all_true(
|
||||
index_sequence<Is...>{},
|
||||
integer_sequence<bool,
|
||||
(is_formattable<typename std::tuple_element<Is, T>::type,
|
||||
C>::value)...>{}));
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
decltype(check(tuple_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
template <typename Tuple, typename F, size_t... Is>
|
||||
FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
|
||||
using std::get;
|
||||
// Using a free function get<Is>(Tuple) now.
|
||||
const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
|
||||
template <typename Tuple, typename F>
|
||||
FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
|
||||
for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
|
||||
std::forward<Tuple>(t), std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
|
||||
void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
|
||||
using std::get;
|
||||
const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
|
||||
template <typename Tuple1, typename Tuple2, typename F>
|
||||
void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
|
||||
for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
|
||||
std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
namespace tuple {
|
||||
// Workaround a bug in MSVC 2019 (v140).
|
||||
template <typename Char, typename... T>
|
||||
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
|
||||
|
||||
using std::get;
|
||||
template <typename Tuple, typename Char, size_t... Is>
|
||||
auto get_formatters(index_sequence<Is...>)
|
||||
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
|
||||
} // namespace tuple
|
||||
|
||||
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
|
||||
// Older MSVC doesn't get the reference type correctly for arrays.
|
||||
template <typename R> struct range_reference_type_impl {
|
||||
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||
};
|
||||
|
||||
template <typename T, size_t N> struct range_reference_type_impl<T[N]> {
|
||||
using type = T&;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using range_reference_type = typename range_reference_type_impl<T>::type;
|
||||
#else
|
||||
template <typename Range>
|
||||
using range_reference_type =
|
||||
decltype(*detail::range_begin(std::declval<Range&>()));
|
||||
#endif
|
||||
|
||||
// We don't use the Range's value_type for anything, but we do need the Range's
|
||||
// reference type, with cv-ref stripped.
|
||||
template <typename Range>
|
||||
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||
|
||||
template <typename Formatter>
|
||||
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
|
||||
-> decltype(f.set_debug_format(set)) {
|
||||
f.set_debug_format(set);
|
||||
}
|
||||
template <typename Formatter>
|
||||
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
|
||||
|
||||
template <typename T>
|
||||
struct range_format_kind_
|
||||
: std::integral_constant<range_format,
|
||||
std::is_same<uncvref_type<T>, T>::value
|
||||
? range_format::disabled
|
||||
: is_map<T>::value ? range_format::map
|
||||
: is_set<T>::value ? range_format::set
|
||||
: range_format::sequence> {};
|
||||
|
||||
template <range_format K>
|
||||
using range_format_constant = std::integral_constant<range_format, K>;
|
||||
|
||||
// These are not generic lambdas for compatibility with C++11.
|
||||
template <typename Char> struct parse_empty_specs {
|
||||
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
|
||||
f.parse(ctx);
|
||||
detail::maybe_set_debug_format(f, true);
|
||||
}
|
||||
parse_context<Char>& ctx;
|
||||
};
|
||||
template <typename FormatContext> struct format_tuple_element {
|
||||
using char_type = typename FormatContext::char_type;
|
||||
|
||||
template <typename T>
|
||||
void operator()(const formatter<T, char_type>& f, const T& v) {
|
||||
if (i > 0) ctx.advance_to(detail::copy<char_type>(separator, ctx.out()));
|
||||
ctx.advance_to(f.format(v, ctx));
|
||||
++i;
|
||||
}
|
||||
|
||||
int i;
|
||||
FormatContext& ctx;
|
||||
basic_string_view<char_type> separator;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T> struct is_tuple_like {
|
||||
static constexpr bool value =
|
||||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename C> struct is_tuple_formattable {
|
||||
static constexpr bool value = detail::is_tuple_formattable_<T, C>::value;
|
||||
};
|
||||
|
||||
template <typename Tuple, typename Char>
|
||||
struct formatter<Tuple, Char,
|
||||
enable_if_t<fmt::is_tuple_like<Tuple>::value &&
|
||||
fmt::is_tuple_formattable<Tuple, Char>::value>> {
|
||||
private:
|
||||
decltype(detail::tuple::get_formatters<Tuple, Char>(
|
||||
detail::tuple_index_sequence<Tuple>())) formatters_;
|
||||
|
||||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||
basic_string_view<Char> opening_bracket_ =
|
||||
detail::string_literal<Char, '('>{};
|
||||
basic_string_view<Char> closing_bracket_ =
|
||||
detail::string_literal<Char, ')'>{};
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR formatter() {}
|
||||
|
||||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||
separator_ = sep;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||
basic_string_view<Char> close) {
|
||||
opening_bracket_ = open;
|
||||
closing_bracket_ = close;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it != end && detail::to_ascii(*it) == 'n') {
|
||||
++it;
|
||||
set_brackets({}, {});
|
||||
set_separator({});
|
||||
}
|
||||
if (it != end && *it != '}') report_error("invalid format specifier");
|
||||
ctx.advance_to(it);
|
||||
detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Tuple& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
ctx.advance_to(detail::copy<Char>(opening_bracket_, ctx.out()));
|
||||
detail::for_each2(
|
||||
formatters_, value,
|
||||
detail::format_tuple_element<FormatContext>{0, ctx, separator_});
|
||||
return detail::copy<Char>(closing_bracket_, ctx.out());
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static constexpr bool value =
|
||||
detail::is_range_<T>::value && !detail::has_to_string_view<T>::value;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename Element>
|
||||
using range_formatter_type = formatter<remove_cvref_t<Element>, Char>;
|
||||
|
||||
template <typename R>
|
||||
using maybe_const_range =
|
||||
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||
|
||||
template <typename R, typename Char>
|
||||
struct is_formattable_delayed
|
||||
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename...> struct conjunction : std::true_type {};
|
||||
template <typename P> struct conjunction<P> : P {};
|
||||
template <typename P1, typename... Pn>
|
||||
struct conjunction<P1, Pn...>
|
||||
: conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_formatter;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct range_formatter<
|
||||
T, Char,
|
||||
enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
|
||||
is_formattable<T, Char>>::value>> {
|
||||
private:
|
||||
detail::range_formatter_type<Char, T> underlying_;
|
||||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||
basic_string_view<Char> opening_bracket_ =
|
||||
detail::string_literal<Char, '['>{};
|
||||
basic_string_view<Char> closing_bracket_ =
|
||||
detail::string_literal<Char, ']'>{};
|
||||
bool is_debug = false;
|
||||
|
||||
template <typename Output, typename It, typename Sentinel, typename U = T,
|
||||
FMT_ENABLE_IF(std::is_same<U, Char>::value)>
|
||||
auto write_debug_string(Output& out, It it, Sentinel end) const -> Output {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
for (; it != end; ++it) buf.push_back(*it);
|
||||
auto specs = format_specs();
|
||||
specs.set_type(presentation_type::debug);
|
||||
return detail::write<Char>(
|
||||
out, basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||
}
|
||||
|
||||
template <typename Output, typename It, typename Sentinel, typename U = T,
|
||||
FMT_ENABLE_IF(!std::is_same<U, Char>::value)>
|
||||
auto write_debug_string(Output& out, It, Sentinel) const -> Output {
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR range_formatter() {}
|
||||
|
||||
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
|
||||
return underlying_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||
separator_ = sep;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||
basic_string_view<Char> close) {
|
||||
opening_bracket_ = open;
|
||||
closing_bracket_ = close;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
detail::maybe_set_debug_format(underlying_, true);
|
||||
if (it == end) return underlying_.parse(ctx);
|
||||
|
||||
switch (detail::to_ascii(*it)) {
|
||||
case 'n':
|
||||
set_brackets({}, {});
|
||||
++it;
|
||||
break;
|
||||
case '?':
|
||||
is_debug = true;
|
||||
set_brackets({}, {});
|
||||
++it;
|
||||
if (it == end || *it != 's') report_error("invalid format specifier");
|
||||
FMT_FALLTHROUGH;
|
||||
case 's':
|
||||
if (!std::is_same<T, Char>::value)
|
||||
report_error("invalid format specifier");
|
||||
if (!is_debug) {
|
||||
set_brackets(detail::string_literal<Char, '"'>{},
|
||||
detail::string_literal<Char, '"'>{});
|
||||
set_separator({});
|
||||
detail::maybe_set_debug_format(underlying_, false);
|
||||
}
|
||||
++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
if (it != end && *it != '}') {
|
||||
if (*it != ':') report_error("invalid format specifier");
|
||||
detail::maybe_set_debug_format(underlying_, false);
|
||||
++it;
|
||||
}
|
||||
|
||||
ctx.advance_to(it);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename R, typename FormatContext>
|
||||
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
auto it = detail::range_begin(range);
|
||||
auto end = detail::range_end(range);
|
||||
if (is_debug) return write_debug_string(out, std::move(it), end);
|
||||
|
||||
out = detail::copy<Char>(opening_bracket_, out);
|
||||
int i = 0;
|
||||
for (; it != end; ++it) {
|
||||
if (i > 0) out = detail::copy<Char>(separator_, out);
|
||||
ctx.advance_to(out);
|
||||
auto&& item = *it; // Need an lvalue
|
||||
out = underlying_.format(item, ctx);
|
||||
++i;
|
||||
}
|
||||
out = detail::copy<Char>(closing_bracket_, out);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_format_kind
|
||||
: conditional_t<
|
||||
is_range<T, Char>::value, detail::range_format_kind_<T>,
|
||||
std::integral_constant<range_format, range_format::disabled>> {};
|
||||
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<conjunction<
|
||||
bool_constant<
|
||||
range_format_kind<R, Char>::value != range_format::disabled &&
|
||||
range_format_kind<R, Char>::value != range_format::map &&
|
||||
range_format_kind<R, Char>::value != range_format::string &&
|
||||
range_format_kind<R, Char>::value != range_format::debug_string>,
|
||||
detail::is_formattable_delayed<R, Char>>::value>> {
|
||||
private:
|
||||
using range_type = detail::maybe_const_range<R>;
|
||||
range_formatter<detail::uncvref_type<range_type>, Char> range_formatter_;
|
||||
|
||||
public:
|
||||
using nonlocking = void;
|
||||
|
||||
FMT_CONSTEXPR formatter() {
|
||||
if (detail::const_check(range_format_kind<R, Char>::value !=
|
||||
range_format::set))
|
||||
return;
|
||||
range_formatter_.set_brackets(detail::string_literal<Char, '{'>{},
|
||||
detail::string_literal<Char, '}'>{});
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return range_formatter_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return range_formatter_.format(range, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// A map formatter.
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<conjunction<
|
||||
bool_constant<range_format_kind<R, Char>::value == range_format::map>,
|
||||
detail::is_formattable_delayed<R, Char>>::value>> {
|
||||
private:
|
||||
using map_type = detail::maybe_const_range<R>;
|
||||
using element_type = detail::uncvref_type<map_type>;
|
||||
|
||||
decltype(detail::tuple::get_formatters<element_type, Char>(
|
||||
detail::tuple_index_sequence<element_type>())) formatters_;
|
||||
bool no_delimiters_ = false;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR formatter() {}
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it != end) {
|
||||
if (detail::to_ascii(*it) == 'n') {
|
||||
no_delimiters_ = true;
|
||||
++it;
|
||||
}
|
||||
if (it != end && *it != '}') {
|
||||
if (*it != ':') report_error("invalid format specifier");
|
||||
++it;
|
||||
}
|
||||
ctx.advance_to(it);
|
||||
}
|
||||
detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
basic_string_view<Char> open = detail::string_literal<Char, '{'>{};
|
||||
if (!no_delimiters_) out = detail::copy<Char>(open, out);
|
||||
int i = 0;
|
||||
basic_string_view<Char> sep = detail::string_literal<Char, ',', ' '>{};
|
||||
for (auto&& value : map) {
|
||||
if (i > 0) out = detail::copy<Char>(sep, out);
|
||||
ctx.advance_to(out);
|
||||
detail::for_each2(formatters_, value,
|
||||
detail::format_tuple_element<FormatContext>{
|
||||
0, ctx, detail::string_literal<Char, ':', ' '>{}});
|
||||
++i;
|
||||
}
|
||||
basic_string_view<Char> close = detail::string_literal<Char, '}'>{};
|
||||
if (!no_delimiters_) out = detail::copy<Char>(close, out);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
// A (debug_)string formatter.
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<range_format_kind<R, Char>::value == range_format::string ||
|
||||
range_format_kind<R, Char>::value ==
|
||||
range_format::debug_string>> {
|
||||
private:
|
||||
using range_type = detail::maybe_const_range<R>;
|
||||
using string_type =
|
||||
conditional_t<std::is_constructible<
|
||||
detail::std_string_view<Char>,
|
||||
decltype(detail::range_begin(std::declval<R>())),
|
||||
decltype(detail::range_end(std::declval<R>()))>::value,
|
||||
detail::std_string_view<Char>, std::basic_string<Char>>;
|
||||
|
||||
formatter<string_type, Char> underlying_;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
if (detail::const_check(range_format_kind<R, Char>::value ==
|
||||
range_format::debug_string))
|
||||
*out++ = '"';
|
||||
out = underlying_.format(
|
||||
string_type{detail::range_begin(range), detail::range_end(range)}, ctx);
|
||||
if (detail::const_check(range_format_kind<R, Char>::value ==
|
||||
range_format::debug_string))
|
||||
*out++ = '"';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename It, typename Sentinel, typename Char = char>
|
||||
struct join_view : detail::view {
|
||||
It begin;
|
||||
Sentinel end;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
join_view(It b, Sentinel e, basic_string_view<Char> s)
|
||||
: begin(std::move(b)), end(e), sep(s) {}
|
||||
};
|
||||
|
||||
template <typename It, typename Sentinel, typename Char>
|
||||
struct formatter<join_view<It, Sentinel, Char>, Char> {
|
||||
private:
|
||||
using value_type =
|
||||
#ifdef __cpp_lib_ranges
|
||||
std::iter_value_t<It>;
|
||||
#else
|
||||
typename std::iterator_traits<It>::value_type;
|
||||
#endif
|
||||
formatter<remove_cvref_t<value_type>, Char> value_formatter_;
|
||||
|
||||
using view = conditional_t<std::is_copy_constructible<It>::value,
|
||||
const join_view<It, Sentinel, Char>,
|
||||
join_view<It, Sentinel, Char>>;
|
||||
|
||||
public:
|
||||
using nonlocking = void;
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return value_formatter_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
using iter =
|
||||
conditional_t<std::is_copy_constructible<view>::value, It, It&>;
|
||||
iter it = value.begin;
|
||||
auto out = ctx.out();
|
||||
if (it == value.end) return out;
|
||||
out = value_formatter_.format(*it, ctx);
|
||||
++it;
|
||||
while (it != value.end) {
|
||||
out = detail::copy<Char>(value.sep.begin(), value.sep.end(), out);
|
||||
ctx.advance_to(out);
|
||||
out = value_formatter_.format(*it, ctx);
|
||||
++it;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Tuple, typename Char> struct tuple_join_view : detail::view {
|
||||
const Tuple& tuple;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
tuple_join_view(const Tuple& t, basic_string_view<Char> s)
|
||||
: tuple(t), sep{s} {}
|
||||
};
|
||||
|
||||
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
|
||||
// support in tuple_join. It is disabled by default because of issues with
|
||||
// the dynamic width and precision.
|
||||
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
|
||||
# define FMT_TUPLE_JOIN_SPECIFIERS 0
|
||||
#endif
|
||||
|
||||
template <typename Tuple, typename Char>
|
||||
struct formatter<tuple_join_view<Tuple, Char>, Char,
|
||||
enable_if_t<is_tuple_like<Tuple>::value>> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return do_parse(ctx, std::tuple_size<Tuple>());
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const tuple_join_view<Tuple, Char>& value,
|
||||
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||
return do_format(value, ctx, std::tuple_size<Tuple>());
|
||||
}
|
||||
|
||||
private:
|
||||
decltype(detail::tuple::get_formatters<Tuple, Char>(
|
||||
detail::tuple_index_sequence<Tuple>())) formatters_;
|
||||
|
||||
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
|
||||
std::integral_constant<size_t, 0>)
|
||||
-> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
|
||||
std::integral_constant<size_t, N>)
|
||||
-> const Char* {
|
||||
auto end = ctx.begin();
|
||||
#if FMT_TUPLE_JOIN_SPECIFIERS
|
||||
end = std::get<std::tuple_size<Tuple>::value - N>(formatters_).parse(ctx);
|
||||
if (N > 1) {
|
||||
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
|
||||
if (end != end1)
|
||||
report_error("incompatible format specs for tuple elements");
|
||||
}
|
||||
#endif
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto do_format(const tuple_join_view<Tuple, Char>&, FormatContext& ctx,
|
||||
std::integral_constant<size_t, 0>) const ->
|
||||
typename FormatContext::iterator {
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
template <typename FormatContext, size_t N>
|
||||
auto do_format(const tuple_join_view<Tuple, Char>& value, FormatContext& ctx,
|
||||
std::integral_constant<size_t, N>) const ->
|
||||
typename FormatContext::iterator {
|
||||
using std::get;
|
||||
auto out =
|
||||
std::get<std::tuple_size<Tuple>::value - N>(formatters_)
|
||||
.format(get<std::tuple_size<Tuple>::value - N>(value.tuple), ctx);
|
||||
if (N <= 1) return out;
|
||||
out = detail::copy<Char>(value.sep, out);
|
||||
ctx.advance_to(out);
|
||||
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
// Check if T has an interface like a container adaptor (e.g. std::stack,
|
||||
// std::queue, std::priority_queue).
|
||||
template <typename T> class is_container_adaptor_like {
|
||||
template <typename U> static auto check(U* p) -> typename U::container_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename Container> struct all {
|
||||
const Container& c;
|
||||
auto begin() const -> typename Container::const_iterator { return c.begin(); }
|
||||
auto end() const -> typename Container::const_iterator { return c.end(); }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char,
|
||||
enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
|
||||
bool_constant<range_format_kind<T, Char>::value ==
|
||||
range_format::disabled>>::value>>
|
||||
: formatter<detail::all<typename T::container_type>, Char> {
|
||||
using all = detail::all<typename T::container_type>;
|
||||
template <typename FormatContext>
|
||||
auto format(const T& value, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
struct getter : T {
|
||||
static auto get(const T& v) -> all {
|
||||
return {v.*(&getter::c)}; // Access c through the derived class.
|
||||
}
|
||||
};
|
||||
return formatter<all>::format(getter::get(value), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
/// Returns a view that formats the iterator range `[begin, end)` with elements
|
||||
/// separated by `sep`.
|
||||
template <typename It, typename Sentinel>
|
||||
auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
|
||||
return {std::move(begin), end, sep};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view that formats `range` with elements separated by `sep`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* auto v = std::vector<int>{1, 2, 3};
|
||||
* fmt::print("{}", fmt::join(v, ", "));
|
||||
* // Output: 1, 2, 3
|
||||
*
|
||||
* `fmt::join` applies passed format specifiers to the range elements:
|
||||
*
|
||||
* fmt::print("{:02}", fmt::join(v, ", "));
|
||||
* // Output: 01, 02, 03
|
||||
*/
|
||||
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
|
||||
auto join(Range&& r, string_view sep)
|
||||
-> join_view<decltype(detail::range_begin(r)),
|
||||
decltype(detail::range_end(r))> {
|
||||
return {detail::range_begin(r), detail::range_end(r), sep};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object that formats `std::tuple` with elements separated by `sep`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* auto t = std::tuple<int, char>{1, 'a'};
|
||||
* fmt::print("{}", fmt::join(t, ", "));
|
||||
* // Output: 1, a
|
||||
*/
|
||||
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
|
||||
FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep)
|
||||
-> tuple_join_view<Tuple, char> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object that formats `std::initializer_list` with elements
|
||||
* separated by `sep`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print("{}", fmt::join({1, 2, 3}, ", "));
|
||||
* // Output: "1, 2, 3"
|
||||
*/
|
||||
template <typename T>
|
||||
auto join(std::initializer_list<T> list, string_view sep)
|
||||
-> join_view<const T*, const T*> {
|
||||
return join(std::begin(list), std::end(list), sep);
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_RANGES_H_
|
||||
|
|
@ -0,0 +1,707 @@
|
|||
// Formatting library for C++ - formatters for standard library types
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_STD_H_
|
||||
#define FMT_STD_H_
|
||||
|
||||
#include "format.h"
|
||||
#include "ostream.h"
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <atomic>
|
||||
# include <bitset>
|
||||
# include <complex>
|
||||
# include <exception>
|
||||
# include <functional> // std::reference_wrapper
|
||||
# include <memory>
|
||||
# include <thread>
|
||||
# include <type_traits>
|
||||
# include <typeinfo> // std::type_info
|
||||
# include <utility> // std::make_index_sequence
|
||||
|
||||
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
|
||||
# if FMT_CPLUSPLUS >= 201703L
|
||||
# if FMT_HAS_INCLUDE(<filesystem>) && \
|
||||
(!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0)
|
||||
# include <filesystem>
|
||||
# endif
|
||||
# if FMT_HAS_INCLUDE(<variant>)
|
||||
# include <variant>
|
||||
# endif
|
||||
# if FMT_HAS_INCLUDE(<optional>)
|
||||
# include <optional>
|
||||
# endif
|
||||
# endif
|
||||
// Use > instead of >= in the version check because <source_location> may be
|
||||
// available after C++17 but before C++20 is marked as implemented.
|
||||
# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>)
|
||||
# include <source_location>
|
||||
# endif
|
||||
# if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE(<expected>)
|
||||
# include <expected>
|
||||
# endif
|
||||
#endif // FMT_MODULE
|
||||
|
||||
#if FMT_HAS_INCLUDE(<version>)
|
||||
# include <version>
|
||||
#endif
|
||||
|
||||
// GCC 4 does not support FMT_HAS_INCLUDE.
|
||||
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
|
||||
# include <cxxabi.h>
|
||||
// Android NDK with gabi++ library on some architectures does not implement
|
||||
// abi::__cxa_demangle().
|
||||
# ifndef __GABIXX_CXXABI_H__
|
||||
# define FMT_HAS_ABI_CXA_DEMANGLE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef FMT_CPP_LIB_FILESYSTEM
|
||||
// Use the provided definition.
|
||||
#elif defined(__cpp_lib_filesystem)
|
||||
# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
|
||||
#else
|
||||
# define FMT_CPP_LIB_FILESYSTEM 0
|
||||
#endif
|
||||
|
||||
#ifdef FMT_CPP_LIB_VARIANT
|
||||
// Use the provided definition.
|
||||
#elif defined(__cpp_lib_variant)
|
||||
# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
|
||||
#else
|
||||
# define FMT_CPP_LIB_VARIANT 0
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
#if FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
auto get_path_string(const std::filesystem::path& p,
|
||||
const std::basic_string<PathChar>& native) {
|
||||
if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>)
|
||||
return to_utf8<wchar_t>(native, to_utf8_error_policy::replace);
|
||||
else
|
||||
return p.string<Char>();
|
||||
}
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||
const std::filesystem::path& p,
|
||||
const std::basic_string<PathChar>& native) {
|
||||
if constexpr (std::is_same_v<Char, char> &&
|
||||
std::is_same_v<PathChar, wchar_t>) {
|
||||
auto buf = basic_memory_buffer<wchar_t>();
|
||||
write_escaped_string<wchar_t>(std::back_inserter(buf), native);
|
||||
bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
|
||||
FMT_ASSERT(valid, "invalid utf16");
|
||||
} else if constexpr (std::is_same_v<Char, PathChar>) {
|
||||
write_escaped_string<std::filesystem::path::value_type>(
|
||||
std::back_inserter(quoted), native);
|
||||
} else {
|
||||
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
|
||||
template <typename Char, typename OutputIt, typename T>
|
||||
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||
if constexpr (has_to_string_view<T>::value)
|
||||
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
|
||||
return write<Char>(out, v);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FMT_CPP_LIB_VARIANT
|
||||
|
||||
template <typename> struct is_variant_like_ : std::false_type {};
|
||||
template <typename... Types>
|
||||
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
|
||||
|
||||
template <typename Variant, typename Char> class is_variant_formattable {
|
||||
template <size_t... Is>
|
||||
static auto check(std::index_sequence<Is...>) -> std::conjunction<
|
||||
is_formattable<std::variant_alternative_t<Is, Variant>, Char>...>;
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(check(
|
||||
std::make_index_sequence<std::variant_size<Variant>::value>()))::value;
|
||||
};
|
||||
|
||||
#endif // FMT_CPP_LIB_VARIANT
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
|
||||
template <typename OutputIt>
|
||||
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
|
||||
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
|
||||
int status = 0;
|
||||
size_t size = 0;
|
||||
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
|
||||
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
|
||||
|
||||
string_view demangled_name_view;
|
||||
if (demangled_name_ptr) {
|
||||
demangled_name_view = demangled_name_ptr.get();
|
||||
|
||||
// Normalization of stdlib inline namespace names.
|
||||
// libc++ inline namespaces.
|
||||
// std::__1::* -> std::*
|
||||
// std::__1::__fs::* -> std::*
|
||||
// libstdc++ inline namespaces.
|
||||
// std::__cxx11::* -> std::*
|
||||
// std::filesystem::__cxx11::* -> std::filesystem::*
|
||||
if (demangled_name_view.starts_with("std::")) {
|
||||
char* begin = demangled_name_ptr.get();
|
||||
char* to = begin + 5; // std::
|
||||
for (char *from = to, *end = begin + demangled_name_view.size();
|
||||
from < end;) {
|
||||
// This is safe, because demangled_name is NUL-terminated.
|
||||
if (from[0] == '_' && from[1] == '_') {
|
||||
char* next = from + 1;
|
||||
while (next < end && *next != ':') next++;
|
||||
if (next[0] == ':' && next[1] == ':') {
|
||||
from = next + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*to++ = *from++;
|
||||
}
|
||||
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
|
||||
}
|
||||
} else {
|
||||
demangled_name_view = string_view(ti.name());
|
||||
}
|
||||
return detail::write_bytes<char>(out, demangled_name_view);
|
||||
# elif FMT_MSC_VERSION
|
||||
const string_view demangled_name(ti.name());
|
||||
for (size_t i = 0; i < demangled_name.size(); ++i) {
|
||||
auto sub = demangled_name;
|
||||
sub.remove_prefix(i);
|
||||
if (sub.starts_with("enum ")) {
|
||||
i += 4;
|
||||
continue;
|
||||
}
|
||||
if (sub.starts_with("class ") || sub.starts_with("union ")) {
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
if (sub.starts_with("struct ")) {
|
||||
i += 6;
|
||||
continue;
|
||||
}
|
||||
if (*sub.begin() != ' ') *out++ = *sub.begin();
|
||||
}
|
||||
return out;
|
||||
# else
|
||||
return detail::write_bytes<char>(out, string_view(ti.name()));
|
||||
# endif
|
||||
}
|
||||
|
||||
#endif // FMT_USE_RTTI
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_flip : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T> struct is_bit_reference_like {
|
||||
static constexpr bool value = std::is_convertible<T, bool>::value &&
|
||||
std::is_nothrow_assignable<T, bool>::value &&
|
||||
has_flip<T>::value;
|
||||
};
|
||||
|
||||
// Workaround for libc++ incompatibility with C++ standard.
|
||||
// According to the Standard, `bitset::operator[] const` returns bool.
|
||||
#if defined(_LIBCPP_VERSION) && !defined(FMT_IMPORT_STD)
|
||||
template <typename C>
|
||||
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_format_as : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_format_as<T, void_t<decltype(format_as(std::declval<const T&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_format_as_member : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_format_as_member<
|
||||
T, void_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
|
||||
return p.get();
|
||||
}
|
||||
template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
|
||||
return p.get();
|
||||
}
|
||||
|
||||
#if FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
class path : public std::filesystem::path {
|
||||
public:
|
||||
auto display_string() const -> std::string {
|
||||
const std::filesystem::path& base = *this;
|
||||
return fmt::format(FMT_STRING("{}"), base);
|
||||
}
|
||||
auto system_string() const -> std::string { return string(); }
|
||||
|
||||
auto generic_display_string() const -> std::string {
|
||||
const std::filesystem::path& base = *this;
|
||||
return fmt::format(FMT_STRING("{:g}"), base);
|
||||
}
|
||||
auto generic_system_string() const -> std::string { return generic_string(); }
|
||||
};
|
||||
|
||||
template <typename Char> struct formatter<std::filesystem::path, Char> {
|
||||
private:
|
||||
format_specs specs_;
|
||||
detail::arg_ref<Char> width_ref_;
|
||||
bool debug_ = false;
|
||||
char path_type_ = 0;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
||||
auto it = ctx.begin(), end = ctx.end();
|
||||
if (it == end) return it;
|
||||
|
||||
it = detail::parse_align(it, end, specs_);
|
||||
if (it == end) return it;
|
||||
|
||||
Char c = *it;
|
||||
if ((c >= '0' && c <= '9') || c == '{')
|
||||
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||
if (it != end && *it == '?') {
|
||||
debug_ = true;
|
||||
++it;
|
||||
}
|
||||
if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::filesystem::path& p, FormatContext& ctx) const {
|
||||
auto specs = specs_;
|
||||
auto path_string =
|
||||
!path_type_ ? p.native()
|
||||
: p.generic_string<std::filesystem::path::value_type>();
|
||||
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||
ctx);
|
||||
if (!debug_) {
|
||||
auto s = detail::get_path_string<Char>(p, path_string);
|
||||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
||||
}
|
||||
auto quoted = basic_memory_buffer<Char>();
|
||||
detail::write_escaped_path(quoted, p, path_string);
|
||||
return detail::write(ctx.out(),
|
||||
basic_string_view<Char>(quoted.data(), quoted.size()),
|
||||
specs);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
template <size_t N, typename Char>
|
||||
struct formatter<std::bitset<N>, Char>
|
||||
: nested_formatter<basic_string_view<Char>, Char> {
|
||||
private:
|
||||
// This is a functor because C++11 doesn't support generic lambdas.
|
||||
struct writer {
|
||||
const std::bitset<N>& bs;
|
||||
|
||||
template <typename OutputIt>
|
||||
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
|
||||
for (auto pos = N; pos > 0; --pos)
|
||||
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0'));
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename FormatContext>
|
||||
auto format(const std::bitset<N>& bs, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return this->write_padded(ctx, writer{bs});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::optional<T>, Char,
|
||||
std::enable_if_t<is_formattable<T, Char>::value>> {
|
||||
private:
|
||||
formatter<T, Char> underlying_;
|
||||
static constexpr basic_string_view<Char> optional =
|
||||
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
|
||||
'('>{};
|
||||
static constexpr basic_string_view<Char> none =
|
||||
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
|
||||
-> decltype(u.set_debug_format(set)) {
|
||||
u.set_debug_format(set);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
||||
maybe_set_debug_format(underlying_, true);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::optional<T>& opt, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
if (!opt) return detail::write<Char>(ctx.out(), none);
|
||||
|
||||
auto out = ctx.out();
|
||||
out = detail::write<Char>(out, optional);
|
||||
ctx.advance_to(out);
|
||||
out = underlying_.format(*opt, ctx);
|
||||
return detail::write(out, ')');
|
||||
}
|
||||
};
|
||||
#endif // __cpp_lib_optional
|
||||
|
||||
#ifdef __cpp_lib_expected
|
||||
template <typename T, typename E, typename Char>
|
||||
struct formatter<std::expected<T, E>, Char,
|
||||
std::enable_if_t<(std::is_void<T>::value ||
|
||||
is_formattable<T, Char>::value) &&
|
||||
is_formattable<E, Char>::value>> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::expected<T, E>& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
|
||||
if (value.has_value()) {
|
||||
out = detail::write<Char>(out, "expected(");
|
||||
if constexpr (!std::is_void<T>::value)
|
||||
out = detail::write_escaped_alternative<Char>(out, *value);
|
||||
} else {
|
||||
out = detail::write<Char>(out, "unexpected(");
|
||||
out = detail::write_escaped_alternative<Char>(out, value.error());
|
||||
}
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
#endif // __cpp_lib_expected
|
||||
|
||||
#ifdef __cpp_lib_source_location
|
||||
template <> struct formatter<std::source_location> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::source_location& loc, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
out = detail::write(out, loc.file_name());
|
||||
out = detail::write(out, ':');
|
||||
out = detail::write<char>(out, loc.line());
|
||||
out = detail::write(out, ':');
|
||||
out = detail::write<char>(out, loc.column());
|
||||
out = detail::write(out, ": ");
|
||||
out = detail::write(out, loc.function_name());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if FMT_CPP_LIB_VARIANT
|
||||
|
||||
template <typename T> struct is_variant_like {
|
||||
static constexpr bool value = detail::is_variant_like_<T>::value;
|
||||
};
|
||||
|
||||
template <typename Char> struct formatter<std::monostate, Char> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::monostate&, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return detail::write<Char>(ctx.out(), "monostate");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Variant, typename Char>
|
||||
struct formatter<Variant, Char,
|
||||
std::enable_if_t<std::conjunction_v<
|
||||
is_variant_like<Variant>,
|
||||
detail::is_variant_formattable<Variant, Char>>>> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Variant& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
|
||||
out = detail::write<Char>(out, "variant(");
|
||||
FMT_TRY {
|
||||
std::visit(
|
||||
[&](const auto& v) {
|
||||
out = detail::write_escaped_alternative<Char>(out, v);
|
||||
},
|
||||
value);
|
||||
}
|
||||
FMT_CATCH(const std::bad_variant_access&) {
|
||||
detail::write<Char>(out, "valueless by exception");
|
||||
}
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // FMT_CPP_LIB_VARIANT
|
||||
|
||||
template <> struct formatter<std::error_code> {
|
||||
private:
|
||||
format_specs specs_;
|
||||
detail::arg_ref<char> width_ref_;
|
||||
bool debug_ = false;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
||||
auto it = ctx.begin(), end = ctx.end();
|
||||
if (it == end) return it;
|
||||
|
||||
it = detail::parse_align(it, end, specs_);
|
||||
|
||||
char c = *it;
|
||||
if (it != end && ((c >= '0' && c <= '9') || c == '{'))
|
||||
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||
|
||||
if (it != end && *it == '?') {
|
||||
debug_ = true;
|
||||
++it;
|
||||
}
|
||||
if (it != end && *it == 's') {
|
||||
specs_.set_type(presentation_type::string);
|
||||
++it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
FMT_CONSTEXPR20 auto format(const std::error_code& ec,
|
||||
FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
auto specs = specs_;
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||
ctx);
|
||||
auto buf = memory_buffer();
|
||||
if (specs_.type() == presentation_type::string) {
|
||||
buf.append(ec.message());
|
||||
} else {
|
||||
buf.append(string_view(ec.category().name()));
|
||||
buf.push_back(':');
|
||||
detail::write<char>(appender(buf), ec.value());
|
||||
}
|
||||
auto quoted = memory_buffer();
|
||||
auto str = string_view(buf.data(), buf.size());
|
||||
if (debug_) {
|
||||
detail::write_escaped_string<char>(std::back_inserter(quoted), str);
|
||||
str = string_view(quoted.data(), quoted.size());
|
||||
}
|
||||
return detail::write<char>(ctx.out(), str, specs);
|
||||
}
|
||||
};
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
template <> struct formatter<std::type_info> {
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
auto format(const std::type_info& ti, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return detail::write_demangled_name(ctx.out(), ti);
|
||||
}
|
||||
};
|
||||
#endif // FMT_USE_RTTI
|
||||
|
||||
template <typename T>
|
||||
struct formatter<
|
||||
T, char,
|
||||
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
|
||||
private:
|
||||
bool with_typename_ = false;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it == end || *it == '}') return it;
|
||||
if (*it == 't') {
|
||||
++it;
|
||||
with_typename_ = FMT_USE_RTTI != 0;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
auto format(const std::exception& ex, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
#if FMT_USE_RTTI
|
||||
if (with_typename_) {
|
||||
out = detail::write_demangled_name(out, typeid(ex));
|
||||
*out++ = ':';
|
||||
*out++ = ' ';
|
||||
}
|
||||
#endif
|
||||
return detail::write_bytes<char>(out, string_view(ex.what()));
|
||||
}
|
||||
};
|
||||
|
||||
// We can't use std::vector<bool, Allocator>::reference and
|
||||
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
|
||||
// in partial specialization.
|
||||
template <typename BitRef, typename Char>
|
||||
struct formatter<BitRef, Char,
|
||||
enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
|
||||
: formatter<bool, Char> {
|
||||
template <typename FormatContext>
|
||||
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<bool, Char>::format(v, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::atomic<T>, Char,
|
||||
enable_if_t<is_formattable<T, Char>::value>>
|
||||
: formatter<T, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const std::atomic<T>& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<T, Char>::format(v.load(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __cpp_lib_atomic_flag_test
|
||||
template <typename Char>
|
||||
struct formatter<std::atomic_flag, Char> : formatter<bool, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const std::atomic_flag& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<bool, Char>::format(v.test(), ctx);
|
||||
}
|
||||
};
|
||||
#endif // __cpp_lib_atomic_flag_test
|
||||
|
||||
template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
|
||||
private:
|
||||
detail::dynamic_format_specs<Char> specs_;
|
||||
|
||||
template <typename FormatContext, typename OutputIt>
|
||||
FMT_CONSTEXPR auto do_format(const std::complex<T>& c,
|
||||
detail::dynamic_format_specs<Char>& specs,
|
||||
FormatContext& ctx, OutputIt out) const
|
||||
-> OutputIt {
|
||||
if (c.real() != 0) {
|
||||
*out++ = Char('(');
|
||||
out = detail::write<Char>(out, c.real(), specs, ctx.locale());
|
||||
specs.set_sign(sign::plus);
|
||||
out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
|
||||
if (!detail::isfinite(c.imag())) *out++ = Char(' ');
|
||||
*out++ = Char('i');
|
||||
*out++ = Char(')');
|
||||
return out;
|
||||
}
|
||||
out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
|
||||
if (!detail::isfinite(c.imag())) *out++ = Char(' ');
|
||||
*out++ = Char('i');
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
|
||||
return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
|
||||
detail::type_constant<T, Char>::value);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::complex<T>& c, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto specs = specs_;
|
||||
if (specs.dynamic()) {
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
|
||||
specs.width_ref, ctx);
|
||||
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||
specs.precision_ref, ctx);
|
||||
}
|
||||
|
||||
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
|
||||
auto outer_specs = format_specs();
|
||||
outer_specs.width = specs.width;
|
||||
outer_specs.copy_fill_from(specs);
|
||||
outer_specs.set_align(specs.align());
|
||||
|
||||
specs.width = 0;
|
||||
specs.set_fill({});
|
||||
specs.set_align(align::none);
|
||||
|
||||
do_format(c, specs, ctx, basic_appender<Char>(buf));
|
||||
return detail::write<Char>(ctx.out(),
|
||||
basic_string_view<Char>(buf.data(), buf.size()),
|
||||
outer_specs);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::reference_wrapper<T>, Char,
|
||||
// Guard against format_as because reference_wrapper is
|
||||
// implicitly convertible to T&.
|
||||
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value &&
|
||||
!detail::has_format_as<T>::value &&
|
||||
!detail::has_format_as_member<T>::value>>
|
||||
: formatter<remove_cvref_t<T>, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_STD_H_
|
||||
356
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/xchar.h
vendored
Normal file
356
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/fmt/xchar.h
vendored
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
// Formatting library for C++ - optional wchar_t and exotic character support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_XCHAR_H_
|
||||
#define FMT_XCHAR_H_
|
||||
|
||||
#include "color.h"
|
||||
#include "format.h"
|
||||
#include "ostream.h"
|
||||
#include "ranges.h"
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <cwchar>
|
||||
# if FMT_USE_LOCALE
|
||||
# include <locale>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
|
||||
|
||||
template <typename S, typename = void> struct format_string_char {};
|
||||
|
||||
template <typename S>
|
||||
struct format_string_char<
|
||||
S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> {
|
||||
using type = char_t<S>;
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
struct format_string_char<
|
||||
S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> {
|
||||
using type = typename S::char_type;
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
using format_string_char_t = typename format_string_char<S>::type;
|
||||
|
||||
inline auto write_loc(basic_appender<wchar_t> out, loc_value value,
|
||||
const format_specs& specs, locale_ref loc) -> bool {
|
||||
#if FMT_USE_LOCALE
|
||||
auto& numpunct =
|
||||
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
|
||||
auto separator = std::wstring();
|
||||
auto grouping = numpunct.grouping();
|
||||
if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep());
|
||||
return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}});
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
|
||||
basic_format_args<buffered_context<Char>> args,
|
||||
locale_ref loc = {}) {
|
||||
static_assert(!std::is_same<Char, char>::value, "");
|
||||
auto out = basic_appender<Char>(buf);
|
||||
parse_format_string(
|
||||
fmt, format_handler<Char>{parse_context<Char>(fmt), {out, args, loc}});
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
using wstring_view = basic_string_view<wchar_t>;
|
||||
using wformat_parse_context = parse_context<wchar_t>;
|
||||
using wformat_context = buffered_context<wchar_t>;
|
||||
using wformat_args = basic_format_args<wformat_context>;
|
||||
using wmemory_buffer = basic_memory_buffer<wchar_t>;
|
||||
|
||||
template <typename Char, typename... T> struct basic_fstring {
|
||||
private:
|
||||
basic_string_view<Char> str_;
|
||||
|
||||
static constexpr int num_static_named_args =
|
||||
detail::count_static_named_args<T...>();
|
||||
|
||||
using checker = detail::format_string_checker<
|
||||
Char, static_cast<int>(sizeof...(T)), num_static_named_args,
|
||||
num_static_named_args != detail::count_named_args<T...>()>;
|
||||
|
||||
using arg_pack = detail::arg_pack<T...>;
|
||||
|
||||
public:
|
||||
using t = basic_fstring;
|
||||
|
||||
template <typename S,
|
||||
FMT_ENABLE_IF(
|
||||
std::is_convertible<const S&, basic_string_view<Char>>::value)>
|
||||
FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) {
|
||||
if (FMT_USE_CONSTEVAL)
|
||||
detail::parse_format_string<Char>(s, checker(s, arg_pack()));
|
||||
}
|
||||
template <typename S,
|
||||
FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
|
||||
std::is_same<typename S::char_type, Char>::value)>
|
||||
FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) {
|
||||
FMT_CONSTEXPR auto sv = basic_string_view<Char>(S());
|
||||
FMT_CONSTEXPR int ignore =
|
||||
(parse_format_string(sv, checker(sv, arg_pack())), 0);
|
||||
detail::ignore_unused(ignore);
|
||||
}
|
||||
basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {}
|
||||
|
||||
operator basic_string_view<Char>() const { return str_; }
|
||||
auto get() const -> basic_string_view<Char> { return str_; }
|
||||
};
|
||||
|
||||
template <typename Char, typename... T>
|
||||
using basic_format_string = basic_fstring<Char, T...>;
|
||||
|
||||
template <typename... T>
|
||||
using wformat_string = typename basic_format_string<wchar_t, T...>::t;
|
||||
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
|
||||
return {{s}};
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
constexpr auto make_wformat_args(T&... args)
|
||||
-> decltype(fmt::make_format_args<wformat_context>(args...)) {
|
||||
return fmt::make_format_args<wformat_context>(args...);
|
||||
}
|
||||
|
||||
#if !FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
inline namespace literals {
|
||||
inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> {
|
||||
return {s};
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
|
||||
template <typename It, typename Sentinel>
|
||||
auto join(It begin, Sentinel end, wstring_view sep)
|
||||
-> join_view<It, Sentinel, wchar_t> {
|
||||
return {begin, end, sep};
|
||||
}
|
||||
|
||||
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
|
||||
auto join(Range&& range, wstring_view sep)
|
||||
-> join_view<decltype(std::begin(range)), decltype(std::end(range)),
|
||||
wchar_t> {
|
||||
return join(std::begin(range), std::end(range), sep);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto join(std::initializer_list<T> list, wstring_view sep)
|
||||
-> join_view<const T*, const T*, wchar_t> {
|
||||
return join(std::begin(list), std::end(list), sep);
|
||||
}
|
||||
|
||||
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
|
||||
auto join(const Tuple& tuple, basic_string_view<wchar_t> sep)
|
||||
-> tuple_join_view<Tuple, wchar_t> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
auto vformat(basic_string_view<Char> fmt,
|
||||
basic_format_args<buffered_context<Char>> args)
|
||||
-> std::basic_string<Char> {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buf, fmt, args);
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
|
||||
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename... T>
|
||||
auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args)
|
||||
-> OutputIt {
|
||||
return vformat_to(out, fmt::wstring_view(fmt),
|
||||
fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
// Pass char_t as a default template parameter instead of using
|
||||
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||
template <typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
|
||||
!std::is_same<Char, wchar_t>::value)>
|
||||
auto format(const S& fmt, T&&... args) -> std::basic_string<Char> {
|
||||
return vformat(detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat(locale_ref loc, const S& fmt,
|
||||
basic_format_args<buffered_context<Char>> args)
|
||||
-> std::basic_string<Char> {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt), args, loc);
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
template <typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||
inline auto format(locale_ref loc, const S& fmt, T&&... args)
|
||||
-> std::basic_string<Char> {
|
||||
return vformat(loc, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
auto vformat_to(OutputIt out, const S& fmt,
|
||||
basic_format_args<buffered_context<Char>> args) -> OutputIt {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt), args);
|
||||
return detail::get_iterator(buf, out);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
|
||||
!std::is_same<Char, char>::value &&
|
||||
!std::is_same<Char, wchar_t>::value)>
|
||||
inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
|
||||
return vformat_to(out, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename S, typename OutputIt, typename... Args,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat_to(OutputIt out, locale_ref loc, const S& fmt,
|
||||
basic_format_args<buffered_context<Char>> args)
|
||||
-> OutputIt {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
vformat_to(buf, detail::to_string_view(fmt), args, loc);
|
||||
return detail::get_iterator(buf, out);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
bool enable = detail::is_output_iterator<OutputIt, Char>::value &&
|
||||
detail::is_exotic_char<Char>::value>
|
||||
inline auto format_to(OutputIt out, locale_ref loc, const S& fmt, T&&... args)
|
||||
-> typename std::enable_if<enable, OutputIt>::type {
|
||||
return vformat_to(out, loc, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
|
||||
basic_format_args<buffered_context<Char>> args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
using traits = detail::fixed_buffer_traits;
|
||||
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
|
||||
detail::vformat_to(buf, fmt, args);
|
||||
return {buf.out(), buf.count()};
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||
inline auto formatted_size(const S& fmt, T&&... args) -> size_t {
|
||||
auto buf = detail::counting_buffer<Char>();
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
return buf.count();
|
||||
}
|
||||
|
||||
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
|
||||
auto buf = wmemory_buffer();
|
||||
detail::vformat_to(buf, fmt, args);
|
||||
buf.push_back(L'\0');
|
||||
if (std::fputws(buf.data(), f) == -1)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
inline void vprint(wstring_view fmt, wformat_args args) {
|
||||
vprint(stdout, fmt, args);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
||||
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
|
||||
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
||||
return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
|
||||
return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
inline auto vformat(text_style ts, wstring_view fmt, wformat_args args)
|
||||
-> std::wstring {
|
||||
auto buf = wmemory_buffer();
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
inline auto format(text_style ts, wformat_string<T...> fmt, T&&... args)
|
||||
-> std::wstring {
|
||||
return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) {
|
||||
auto buffer = basic_memory_buffer<wchar_t>();
|
||||
detail::vformat_to(buffer, fmt, args);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
|
||||
vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
|
||||
print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
/// Converts `value` to `std::wstring` using the default format for type `T`.
|
||||
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
|
||||
return format(FMT_STRING(L"{}"), value);
|
||||
}
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_XCHAR_H_
|
||||
1491
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/widechar_width.hpp
vendored
Normal file
1491
libs/external/chat-vault/monitoring/grafana/monitor-tui/include/widechar_width.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,70 @@
|
|||
% btop(1) | User Commands
|
||||
%
|
||||
% 2025-05-01
|
||||
|
||||
# NAME
|
||||
|
||||
btop - Resource monitor that shows usage and stats for processor, memory, disks, network, and processes.
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**btop** [**-c**] [**-d**] [**-l**] [**-t**] [**-p** _id_] [**-u** _ms_] [**\-\-force-utf**] [**\-\-themes-dir** _dir_]
|
||||
|
||||
**btop** [{**-h** | **\-\-help**} | {**-V** | **\-\-version**}]
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
**btop** is a program that shows usage and stats for processor, memory, disks, network, and processes.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
The program follows the usual GNU command line syntax, with long options
|
||||
starting with two dashes ('-'). A summary of options is included below.
|
||||
|
||||
**-c**, **\-\-config _file_**
|
||||
: Path to a config file.
|
||||
|
||||
**-d**, **\-\-debug**
|
||||
: Start in debug mode with additional logs and metrics.
|
||||
|
||||
**-f**, **\-\-filter _filter_**
|
||||
: Set an initial process filter.
|
||||
|
||||
**\-\-force-utf**
|
||||
: Force start even if no UTF-8 locale was detected.
|
||||
|
||||
**-l**, **\-\-low-color**
|
||||
: Disable true color, 256 colors only.
|
||||
|
||||
**-p**, **\-\-preset _id_**
|
||||
: Start with a preset (0-9).
|
||||
|
||||
**-t**, **\-\-tty-on**
|
||||
: Force tty mode with ANSI graph symbols and 16 colors only.
|
||||
|
||||
**\-\-tty-off**
|
||||
: Force disable tty mode.
|
||||
|
||||
**\-\-themes-dir _dir_**
|
||||
: Path to a custom themes directory. When specified, this directory takes priority over the default theme search paths.
|
||||
|
||||
**-u**, **\-\-update _ms_**
|
||||
: Set an initial update rate in milliseconds.
|
||||
|
||||
**-h**, **\-\-help**
|
||||
: Show summary of options.
|
||||
|
||||
**-V**, **\-\-version**
|
||||
: Show version of program.
|
||||
|
||||
# BUGS
|
||||
|
||||
The upstream bug tracker can be found at https://github.com/aristocratos/btop/issues.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
**top**(1), **htop**(1)
|
||||
|
||||
# AUTHOR
|
||||
|
||||
**btop** was written by Jakob P. Liljenberg a.k.a. "Aristocratos".
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
if [ -x "$DIR/bin/btop" ]; then
|
||||
exec "$DIR/bin/btop" "$@"
|
||||
elif [ -x "$DIR/build/btop" ]; then
|
||||
exec "$DIR/build/btop" "$@"
|
||||
else
|
||||
echo "btop binary not found; run make first" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
name: btop
|
||||
adopt-info: btop
|
||||
summary: Resource monitor that shows usage and stats
|
||||
description: |
|
||||
Resource monitor that shows usage and stats for processor, memory, disks, network and processes.
|
||||
C++ version and continuation of bashtop and bpytop.
|
||||
license: Apache-2.0
|
||||
|
||||
base: core24
|
||||
grade: stable
|
||||
confinement: strict
|
||||
compression: lzo
|
||||
|
||||
contact: https://github.com/kz6fittycent/btop/issues
|
||||
issues: https://github.com/kz6fittycent/btop/issues
|
||||
source-code: https://github.com/aristocratos/btop
|
||||
|
||||
platforms:
|
||||
amd64:
|
||||
build-on: [amd64]
|
||||
build-for: [amd64]
|
||||
arm64:
|
||||
build-on: [arm64]
|
||||
build-for: [arm64]
|
||||
|
||||
apps:
|
||||
btop:
|
||||
command: usr/local/bin/btop
|
||||
environment:
|
||||
LC_ALL: C.UTF-8
|
||||
LANG: C.UTF-8
|
||||
plugs:
|
||||
- mount-observe
|
||||
- process-control
|
||||
- system-observe
|
||||
- hardware-observe
|
||||
- network
|
||||
- network-observe
|
||||
- home
|
||||
- removable-media
|
||||
- opengl
|
||||
|
||||
parts:
|
||||
btop:
|
||||
source: https://github.com/aristocratos/btop
|
||||
source-type: git
|
||||
plugin: make
|
||||
make-parameters:
|
||||
- CC=gcc-14
|
||||
- CXX=g++-14
|
||||
- PREFIX=/usr/local
|
||||
- STATIC=true #required
|
||||
- ADDFLAGS="-D SNAPPED" #required
|
||||
build-packages:
|
||||
- coreutils
|
||||
- sed
|
||||
- git
|
||||
- build-essential
|
||||
- gcc-14
|
||||
- g++-14
|
||||
|
||||
override-pull: |
|
||||
craftctl default
|
||||
craftctl set version="$(git describe --tags | sed 's/^v//' | cut -d "-" -f1)"
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,4 @@
|
|||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
[[nodiscard]] auto btop_main(std::span<const std::string_view> args) -> int;
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "btop_cli.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <expected>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/base.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "btop_shared.hpp"
|
||||
#include "config.h"
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
static constexpr auto BOLD = "\033[1m"sv;
|
||||
static constexpr auto BOLD_UNDERLINE = "\033[1;4m"sv;
|
||||
static constexpr auto BOLD_RED = "\033[1;31m"sv;
|
||||
static constexpr auto YELLOW = "\033[33m"sv;
|
||||
static constexpr auto RESET = "\033[0m"sv;
|
||||
|
||||
static void version() noexcept {
|
||||
if constexpr (GIT_COMMIT.empty()) {
|
||||
fmt::println("btop version: {}{}{}", BOLD, Global::Version, RESET);
|
||||
} else {
|
||||
fmt::println("btop version: {}{}+{}{}", BOLD, Global::Version, GIT_COMMIT, RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void build_info() noexcept {
|
||||
fmt::println("Compiled with: {} ({})", COMPILER, COMPILER_VERSION);
|
||||
fmt::println("Configured with: {}", CONFIGURE_COMMAND);
|
||||
}
|
||||
|
||||
static void error(std::string_view msg) noexcept {
|
||||
fmt::println("{}error:{} {}\n", BOLD_RED, RESET, msg);
|
||||
}
|
||||
|
||||
namespace Cli {
|
||||
[[nodiscard]] auto parse(const std::span<const std::string_view> args) noexcept -> Result {
|
||||
Cli cli {};
|
||||
|
||||
for (auto it = args.begin(); it != args.end(); ++it) {
|
||||
auto arg = *it;
|
||||
|
||||
if (arg == "-h" || arg == "--help") {
|
||||
usage();
|
||||
help();
|
||||
return std::unexpected { 0 };
|
||||
}
|
||||
if (arg == "-v" || arg == "-V") {
|
||||
version();
|
||||
return std::unexpected { 0 };
|
||||
}
|
||||
if (arg == "--version") {
|
||||
version();
|
||||
build_info();
|
||||
return std::unexpected { 0 };
|
||||
}
|
||||
|
||||
if (arg == "-d" || arg == "--debug") {
|
||||
cli.debug = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "--force-utf") {
|
||||
cli.force_utf = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-l" || arg == "--low-color") {
|
||||
cli.low_color = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-t" || arg == "--tty") {
|
||||
if (cli.force_tty.has_value()) {
|
||||
error("tty mode can't be set twice");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
cli.force_tty = std::make_optional(true);
|
||||
continue;
|
||||
}
|
||||
if (arg == "--no-tty") {
|
||||
if (cli.force_tty.has_value()) {
|
||||
error("tty mode can't be set twice");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
cli.force_tty = std::make_optional(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "-c" || arg == "--config") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Config requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
auto config_file = stdfs::path { arg };
|
||||
|
||||
if (stdfs::is_directory(config_file)) {
|
||||
error("Config file can't be a directory");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
cli.config_file = std::make_optional(config_file);
|
||||
continue;
|
||||
}
|
||||
if (arg == "-f" || arg == "--filter") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Filter requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
cli.filter = std::make_optional(arg);
|
||||
continue;
|
||||
}
|
||||
if (arg == "-p" || arg == "--preset") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Preset requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
try {
|
||||
auto preset_id = std::clamp(std::stoi(arg.data()), 0, 9);
|
||||
cli.preset = std::make_optional(preset_id);
|
||||
} catch (std::invalid_argument& e) {
|
||||
error("Preset must be a positive number");
|
||||
return std::unexpected { 1 };
|
||||
} catch (std::out_of_range& e) {
|
||||
error(fmt::format("Preset argument is out of range: {}", arg.data()));
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (arg == "--themes-dir") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Themes directory requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
auto themes_dir = stdfs::path { arg };
|
||||
|
||||
if (not stdfs::is_directory(themes_dir)) {
|
||||
error("Themes directory does not exist or is not a directory");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
cli.themes_dir = std::make_optional(themes_dir);
|
||||
continue;
|
||||
}
|
||||
if (arg == "-u" || arg == "--update") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Update requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
try {
|
||||
auto refresh_rate = std::max(std::stoi(arg.data()), 100);
|
||||
cli.updates = refresh_rate;
|
||||
} catch (std::invalid_argument& e) {
|
||||
error("Update must be a positive number");
|
||||
return std::unexpected { 1 };
|
||||
} catch (std::out_of_range& e) {
|
||||
error(fmt::format("Update argument is out of range: {}", arg.data()));
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
error(fmt::format("Unknown argument '{}{}{}'", YELLOW, arg, RESET));
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
return cli;
|
||||
}
|
||||
|
||||
void usage() noexcept {
|
||||
fmt::println("{0}Usage:{1} {2}btop{1} [OPTIONS]\n", BOLD_UNDERLINE, RESET, BOLD);
|
||||
}
|
||||
|
||||
void help() noexcept {
|
||||
fmt::print(
|
||||
"{0}Options:{1}\n"
|
||||
" {2}-c, --config{1} <file> Path to a config file\n"
|
||||
" {2}-d, --debug{1} Start in debug mode with additional logs and metrics\n"
|
||||
" {2}-f, --filter{1} <filter> Set an initial process filter\n"
|
||||
" {2} --force-utf{1} Override automatic UTF locale detection\n"
|
||||
" {2}-l, --low-color{1} Disable true color, 256 colors only\n"
|
||||
" {2}-p, --preset{1} <id> Start with a preset (0-9)\n"
|
||||
" {2}-t, --tty{1} Force tty mode with ANSI graph symbols and 16 colors only\n"
|
||||
" {2} --themes-dir{1} <dir> Path to a custom themes directory\n"
|
||||
" {2} --no-tty{1} Force disable tty mode\n"
|
||||
" {2}-u, --update{1} <ms> Set an initial update rate in milliseconds\n"
|
||||
" {2}-h, --help{1} Show this help message and exit\n"
|
||||
" {2}-V, --version{1} Show a version message and exit (more with --version)\n",
|
||||
BOLD_UNDERLINE, RESET, BOLD
|
||||
);
|
||||
}
|
||||
|
||||
void help_hint() noexcept {
|
||||
fmt::println("For more information, try '{}--help{}'", BOLD, RESET);
|
||||
}
|
||||
} // namespace Cli
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
namespace Cli {
|
||||
namespace stdfs = std::filesystem;
|
||||
|
||||
// Configuration options set via the command line.
|
||||
struct Cli {
|
||||
// Alternate path to a configuration file
|
||||
std::optional<stdfs::path> config_file;
|
||||
// Enable debug mode with additional logs and metrics
|
||||
bool debug {};
|
||||
// Set an initial process filter.
|
||||
std::optional<std::string> filter;
|
||||
// Only use ANSI supported graph symbols and colors
|
||||
std::optional<bool> force_tty;
|
||||
// Use UTF-8 locale even if not detected
|
||||
bool force_utf {};
|
||||
// Disable true color and only use 256 color mode
|
||||
bool low_color {};
|
||||
// Start with one of the provided presets
|
||||
std::optional<std::uint32_t> preset;
|
||||
// Path to a custom themes directory
|
||||
std::optional<stdfs::path> themes_dir;
|
||||
// The initial refresh rate
|
||||
std::optional<std::uint32_t> updates;
|
||||
};
|
||||
|
||||
using Result = std::expected<Cli, std::int32_t>;
|
||||
|
||||
// Parse the command line arguments
|
||||
[[nodiscard]] auto parse(std::span<const std::string_view> args) noexcept -> Result;
|
||||
|
||||
// Print a usage header
|
||||
void usage() noexcept;
|
||||
|
||||
// Print a help message
|
||||
void help() noexcept;
|
||||
|
||||
// Print a hint on how to show more help
|
||||
void help_hint() noexcept;
|
||||
} // namespace Cli
|
||||
831
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/btop_config.cpp
vendored
Normal file
831
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/btop_config.cpp
vendored
Normal file
|
|
@ -0,0 +1,831 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include "btop_config.hpp"
|
||||
#include "btop_shared.hpp"
|
||||
#include "btop_tools.hpp"
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::string_view;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace rng = std::ranges;
|
||||
|
||||
using namespace std::literals;
|
||||
using namespace Tools;
|
||||
|
||||
//* Functions and variables for reading and writing the btop config file
|
||||
namespace Config {
|
||||
|
||||
atomic<bool> locked (false);
|
||||
atomic<bool> writelock (false);
|
||||
bool write_new;
|
||||
|
||||
const vector<array<string, 2>> descriptions = {
|
||||
{"color_theme", "#* Name of a btop++/bpytop/bashtop formatted \".theme\" file, \"Default\" and \"TTY\" for builtin themes.\n"
|
||||
"#* Themes should be placed in \"../share/btop/themes\" relative to binary or \"$HOME/.config/btop/themes\""},
|
||||
|
||||
{"theme_background", "#* If the theme set background should be shown, set to False if you want terminal background transparency."},
|
||||
|
||||
{"truecolor", "#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false."},
|
||||
|
||||
{"force_tty", "#* Set to true to force tty mode regardless if a real tty has been detected or not.\n"
|
||||
"#* Will force 16-color mode and TTY theme, set all graph symbols to \"tty\" and swap out other non tty friendly symbols."},
|
||||
|
||||
{"presets", "#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets.\n"
|
||||
"#* Format: \"box_name:P:G,box_name:P:G\" P=(0 or 1) for alternate positions, G=graph symbol to use for box.\n"
|
||||
"#* Use whitespace \" \" as separator between different presets.\n"
|
||||
"#* Example: \"cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty\""},
|
||||
|
||||
{"vim_keys", "#* Set to True to enable \"h,j,k,l,g,G\" keys for directional control in lists.\n"
|
||||
"#* Conflicting keys for h:\"help\" and k:\"kill\" is accessible while holding shift."},
|
||||
|
||||
{"rounded_corners", "#* Rounded corners on boxes, is ignored if TTY mode is ON."},
|
||||
|
||||
{"terminal_sync", "#* Use terminal synchronized output sequences to reduce flickering on supported terminals."},
|
||||
|
||||
{"graph_symbol", "#* Default symbols to use for graph creation, \"braille\", \"block\" or \"tty\".\n"
|
||||
"#* \"braille\" offers the highest resolution but might not be included in all fonts.\n"
|
||||
"#* \"block\" has half the resolution of braille but uses more common characters.\n"
|
||||
"#* \"tty\" uses only 3 different symbols but will work with most fonts and should work in a real TTY.\n"
|
||||
"#* Note that \"tty\" only has half the horizontal resolution of the other two, so will show a shorter historical view."},
|
||||
|
||||
{"graph_symbol_cpu", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
#ifdef GPU_SUPPORT
|
||||
{"graph_symbol_gpu", "# Graph symbol to use for graphs in gpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
#endif
|
||||
{"graph_symbol_mem", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
|
||||
{"graph_symbol_net", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
|
||||
{"graph_symbol_proc", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
|
||||
{"shown_boxes", "#* Manually set which boxes to show. Available values are \"cpu mem net proc\" and \"gpu0\" through \"gpu5\", separate values with whitespace."},
|
||||
|
||||
{"update_ms", "#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs."},
|
||||
|
||||
{"proc_sorting", "#* Processes sorting, \"pid\" \"program\" \"arguments\" \"threads\" \"user\" \"memory\" \"cpu lazy\" \"cpu direct\",\n"
|
||||
"#* \"cpu lazy\" sorts top process over time (easier to follow), \"cpu direct\" updates top process directly."},
|
||||
|
||||
{"proc_reversed", "#* Reverse sorting order, True or False."},
|
||||
|
||||
{"proc_tree", "#* Show processes as a tree."},
|
||||
|
||||
{"proc_colors", "#* Use the cpu graph colors in the process list."},
|
||||
|
||||
{"proc_gradient", "#* Use a darkening gradient in the process list."},
|
||||
|
||||
{"proc_per_core", "#* If process cpu usage should be of the core it's running on or usage of the total available cpu power."},
|
||||
|
||||
{"proc_mem_bytes", "#* Show process memory as bytes instead of percent."},
|
||||
|
||||
{"proc_cpu_graphs", "#* Show cpu graph for each process."},
|
||||
|
||||
{"proc_info_smaps", "#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate)"},
|
||||
|
||||
{"proc_left", "#* Show proc box on left side of screen instead of right."},
|
||||
|
||||
{"proc_filter_kernel", "#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop)."},
|
||||
|
||||
{"proc_aggregate", "#* In tree-view, always accumulate child process resources in the parent process."},
|
||||
|
||||
{"keep_dead_proc_usage", "#* Should cpu and memory usage display be preserved for dead processes when paused."},
|
||||
|
||||
{"cpu_graph_upper", "#* Sets the CPU stat shown in upper half of the CPU graph, \"total\" is always available.\n"
|
||||
"#* Select from a list of detected attributes from the options menu."},
|
||||
|
||||
{"cpu_graph_lower", "#* Sets the CPU stat shown in lower half of the CPU graph, \"total\" is always available.\n"
|
||||
"#* Select from a list of detected attributes from the options menu."},
|
||||
#ifdef GPU_SUPPORT
|
||||
{"show_gpu_info", "#* If gpu info should be shown in the cpu box. Available values = \"Auto\", \"On\" and \"Off\"."},
|
||||
#endif
|
||||
{"cpu_invert_lower", "#* Toggles if the lower CPU graph should be inverted."},
|
||||
|
||||
{"cpu_single_graph", "#* Set to True to completely disable the lower CPU graph."},
|
||||
|
||||
{"cpu_bottom", "#* Show cpu box at bottom of screen instead of top."},
|
||||
|
||||
{"show_uptime", "#* Shows the system uptime in the CPU box."},
|
||||
|
||||
{"show_cpu_watts", "#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo."},
|
||||
|
||||
{"check_temp", "#* Show cpu temperature."},
|
||||
|
||||
{"cpu_sensor", "#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors."},
|
||||
|
||||
{"show_coretemp", "#* Show temperatures for cpu cores also if check_temp is True and sensors has been found."},
|
||||
|
||||
{"cpu_core_map", "#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core.\n"
|
||||
"#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine.\n"
|
||||
"#* Format \"x:y\" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries.\n"
|
||||
"#* Example: \"4:0 5:1 6:3\""},
|
||||
|
||||
{"temp_scale", "#* Which temperature scale to use, available values: \"celsius\", \"fahrenheit\", \"kelvin\" and \"rankine\"."},
|
||||
|
||||
{"base_10_sizes", "#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024."},
|
||||
|
||||
{"show_cpu_freq", "#* Show CPU frequency."},
|
||||
#ifdef __linux__
|
||||
{"freq_mode", "#* How to calculate CPU frequency, available values: \"first\", \"range\", \"lowest\", \"highest\" and \"average\"."},
|
||||
#endif
|
||||
{"clock_format", "#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.\n"
|
||||
"#* Special formatting: /host = hostname | /user = username | /uptime = system uptime"},
|
||||
|
||||
{"background_update", "#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort."},
|
||||
|
||||
{"custom_cpu_name", "#* Custom cpu model name, empty string to disable."},
|
||||
|
||||
{"disks_filter", "#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace \" \".\n"
|
||||
"#* Only disks matching the filter will be shown. Prepend exclude= to only show disks not matching the filter. Examples: disk_filter=\"/boot /home/user\", disks_filter=\"exclude=/boot /home/user\""},
|
||||
|
||||
{"mem_graphs", "#* Show graphs instead of meters for memory values."},
|
||||
|
||||
{"mem_below_net", "#* Show mem box below net box instead of above."},
|
||||
|
||||
{"zfs_arc_cached", "#* Count ZFS ARC in cached and available memory."},
|
||||
|
||||
{"show_swap", "#* If swap memory should be shown in memory box."},
|
||||
|
||||
{"swap_disk", "#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk."},
|
||||
|
||||
{"show_disks", "#* If mem box should be split to also show disks info."},
|
||||
|
||||
{"only_physical", "#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar."},
|
||||
|
||||
{"use_fstab", "#* Read disks list from /etc/fstab. This also disables only_physical."},
|
||||
|
||||
{"zfs_hide_datasets", "#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool)"},
|
||||
|
||||
{"disk_free_priv", "#* Set to true to show available disk space for privileged users."},
|
||||
|
||||
{"show_io_stat", "#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view."},
|
||||
|
||||
{"io_mode", "#* Toggles io mode for disks, showing big graphs for disk read/write speeds."},
|
||||
|
||||
{"io_graph_combined", "#* Set to True to show combined read/write io graphs in io mode."},
|
||||
|
||||
{"io_graph_speeds", "#* Set the top speed for the io graphs in MiB/s (100 by default), use format \"mountpoint:speed\" separate disks with whitespace \" \".\n"
|
||||
"#* Example: \"/mnt/media:100 /:20 /boot:1\"."},
|
||||
|
||||
{"net_download", "#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False."},
|
||||
|
||||
{"net_upload", ""},
|
||||
|
||||
{"net_auto", "#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest."},
|
||||
|
||||
{"net_sync", "#* Sync the auto scaling for download and upload to whichever currently has the highest scale."},
|
||||
|
||||
{"net_iface", "#* Starts with the Network Interface specified here."},
|
||||
|
||||
{"base_10_bitrate", "#* \"True\" shows bitrates in base 10 (Kbps, Mbps). \"False\" shows bitrates in binary sizes (Kibps, Mibps, etc.). \"Auto\" uses base_10_sizes."},
|
||||
|
||||
{"show_battery", "#* Show battery stats in top right if battery is present."},
|
||||
|
||||
{"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."},
|
||||
|
||||
{"show_battery_watts", "#* Show power stats of battery next to charge indicator."},
|
||||
|
||||
{"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
|
||||
"#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."},
|
||||
#ifdef GPU_SUPPORT
|
||||
|
||||
{"nvml_measure_pcie_speeds",
|
||||
"#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards."},
|
||||
{"rsmi_measure_pcie_speeds",
|
||||
"#* Measure PCIe throughput on AMD cards, may impact performance on certain cards."},
|
||||
{"gpu_mirror_graph", "#* Horizontally mirror the GPU graph."},
|
||||
{"shown_gpus", "#* Set which GPU vendors to show. Available values are \"nvidia amd intel\""},
|
||||
{"custom_gpu_name0", "#* Custom gpu0 model name, empty string to disable."},
|
||||
{"custom_gpu_name1", "#* Custom gpu1 model name, empty string to disable."},
|
||||
{"custom_gpu_name2", "#* Custom gpu2 model name, empty string to disable."},
|
||||
{"custom_gpu_name3", "#* Custom gpu3 model name, empty string to disable."},
|
||||
{"custom_gpu_name4", "#* Custom gpu4 model name, empty string to disable."},
|
||||
{"custom_gpu_name5", "#* Custom gpu5 model name, empty string to disable."},
|
||||
#endif
|
||||
};
|
||||
|
||||
std::unordered_map<std::string_view, string> strings = {
|
||||
{"color_theme", "Default"},
|
||||
{"shown_boxes", "net proc"},
|
||||
{"graph_symbol", "braille"},
|
||||
{"presets", "net:0:default,proc:0:default"},
|
||||
{"graph_symbol_cpu", "default"},
|
||||
{"graph_symbol_gpu", "default"},
|
||||
{"graph_symbol_mem", "default"},
|
||||
{"graph_symbol_net", "default"},
|
||||
{"graph_symbol_proc", "default"},
|
||||
{"proc_sorting", "cpu lazy"},
|
||||
{"cpu_graph_upper", "Auto"},
|
||||
{"cpu_graph_lower", "Auto"},
|
||||
{"cpu_sensor", "Auto"},
|
||||
{"selected_battery", "Auto"},
|
||||
{"cpu_core_map", ""},
|
||||
{"temp_scale", "celsius"},
|
||||
#ifdef __linux__
|
||||
{"freq_mode", "first"},
|
||||
#endif
|
||||
{"clock_format", "%X"},
|
||||
{"custom_cpu_name", ""},
|
||||
{"disks_filter", ""},
|
||||
{"io_graph_speeds", ""},
|
||||
{"net_iface", ""},
|
||||
{"base_10_bitrate", "Auto"},
|
||||
{"log_level", "WARNING"},
|
||||
{"proc_filter", ""},
|
||||
{"proc_command", ""},
|
||||
{"selected_name", ""},
|
||||
#ifdef GPU_SUPPORT
|
||||
{"custom_gpu_name0", ""},
|
||||
{"custom_gpu_name1", ""},
|
||||
{"custom_gpu_name2", ""},
|
||||
{"custom_gpu_name3", ""},
|
||||
{"custom_gpu_name4", ""},
|
||||
{"custom_gpu_name5", ""},
|
||||
{"show_gpu_info", "Auto"},
|
||||
{"shown_gpus", "nvidia amd intel"}
|
||||
#endif
|
||||
};
|
||||
std::unordered_map<std::string_view, string> stringsTmp;
|
||||
|
||||
std::unordered_map<std::string_view, bool> bools = {
|
||||
{"theme_background", true},
|
||||
{"truecolor", true},
|
||||
{"rounded_corners", true},
|
||||
{"proc_reversed", false},
|
||||
{"proc_tree", false},
|
||||
{"proc_colors", true},
|
||||
{"proc_gradient", true},
|
||||
{"proc_per_core", false},
|
||||
{"proc_mem_bytes", true},
|
||||
{"proc_cpu_graphs", true},
|
||||
{"proc_info_smaps", false},
|
||||
{"proc_left", false},
|
||||
{"proc_filter_kernel", false},
|
||||
{"cpu_invert_lower", true},
|
||||
{"cpu_single_graph", false},
|
||||
{"cpu_bottom", false},
|
||||
{"show_uptime", true},
|
||||
{"show_cpu_watts", true},
|
||||
{"check_temp", true},
|
||||
{"show_coretemp", true},
|
||||
{"show_cpu_freq", true},
|
||||
{"background_update", true},
|
||||
{"mem_graphs", true},
|
||||
{"mem_below_net", false},
|
||||
{"zfs_arc_cached", true},
|
||||
{"show_swap", true},
|
||||
{"swap_disk", true},
|
||||
{"show_disks", true},
|
||||
{"only_physical", true},
|
||||
{"use_fstab", true},
|
||||
{"zfs_hide_datasets", false},
|
||||
{"show_io_stat", true},
|
||||
{"io_mode", false},
|
||||
{"base_10_sizes", false},
|
||||
{"io_graph_combined", false},
|
||||
{"net_auto", true},
|
||||
{"net_sync", true},
|
||||
{"show_battery", true},
|
||||
{"show_battery_watts", true},
|
||||
{"vim_keys", false},
|
||||
{"tty_mode", false},
|
||||
{"disk_free_priv", false},
|
||||
{"force_tty", false},
|
||||
{"lowcolor", false},
|
||||
{"show_detailed", false},
|
||||
{"proc_filtering", false},
|
||||
{"proc_aggregate", false},
|
||||
{"pause_proc_list", false},
|
||||
{"keep_dead_proc_usage", false},
|
||||
#ifdef GPU_SUPPORT
|
||||
{"nvml_measure_pcie_speeds", true},
|
||||
{"rsmi_measure_pcie_speeds", true},
|
||||
{"gpu_mirror_graph", true},
|
||||
#endif
|
||||
{"terminal_sync", true}
|
||||
};
|
||||
std::unordered_map<std::string_view, bool> boolsTmp;
|
||||
|
||||
std::unordered_map<std::string_view, int> ints = {
|
||||
{"update_ms", 2000},
|
||||
{"net_download", 100},
|
||||
{"net_upload", 100},
|
||||
{"detailed_pid", 0},
|
||||
{"selected_pid", 0},
|
||||
{"selected_depth", 0},
|
||||
{"proc_start", 0},
|
||||
{"proc_selected", 0},
|
||||
{"proc_last_selected", 0}
|
||||
};
|
||||
std::unordered_map<std::string_view, int> intsTmp;
|
||||
|
||||
// Returns a valid config dir or an empty optional
|
||||
// The config dir might be read only, a warning is printed, but a path is returned anyway
|
||||
[[nodiscard]] std::optional<fs::path> get_config_dir() noexcept {
|
||||
fs::path config_dir;
|
||||
{
|
||||
std::error_code error;
|
||||
if (const auto xdg_config_home = std::getenv("XDG_CONFIG_HOME"); xdg_config_home != nullptr) {
|
||||
if (fs::exists(xdg_config_home, error)) {
|
||||
config_dir = fs::path(xdg_config_home) / "btop";
|
||||
}
|
||||
} else if (const auto home = std::getenv("HOME"); home != nullptr) {
|
||||
error.clear();
|
||||
if (fs::exists(home, error)) {
|
||||
config_dir = fs::path(home) / ".config" / "btop";
|
||||
}
|
||||
if (error) {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0m{} could not be accessed: {}\n", config_dir.string(), error.message());
|
||||
config_dir = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This warnings can be noisy if the user deliberately has a non-writable config dir
|
||||
// offer an alternative | disable messages by default | disable messages if config dir is not writable | disable messages with a flag
|
||||
// FIXME: Make happy path not branch
|
||||
if (not config_dir.empty()) {
|
||||
std::error_code error;
|
||||
if (fs::exists(config_dir, error)) {
|
||||
if (fs::is_directory(config_dir, error)) {
|
||||
struct statvfs stats {};
|
||||
if ((fs::status(config_dir, error).permissions() & fs::perms::owner_write) == fs::perms::owner_write and
|
||||
statvfs(config_dir.c_str(), &stats) == 0 and (stats.f_flag & ST_RDONLY) == 0) {
|
||||
return config_dir;
|
||||
} else {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` is not writable\n", fs::absolute(config_dir).string());
|
||||
// If the config is readable we can still use the provided config, but changes will not be persistent
|
||||
if ((fs::status(config_dir, error).permissions() & fs::perms::owner_read) == fs::perms::owner_read) {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0mLogging is disabled, config changes are not persistent\n");
|
||||
return config_dir;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` is not a directory\n", fs::absolute(config_dir).string());
|
||||
}
|
||||
} else {
|
||||
// Doesn't exist
|
||||
if (fs::create_directories(config_dir, error)) {
|
||||
return config_dir;
|
||||
} else {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` could not be created: {}\n", fs::absolute(config_dir).string(), error.message());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0mCould not determine config path: Make sure `$XDG_CONFIG_HOME` or `$HOME` is set\n");
|
||||
}
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0mLogging is disabled, config changes are not persistent\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
bool _locked(const std::string_view name) {
|
||||
atomic_wait(writelock, true);
|
||||
if (not write_new and rng::find_if(descriptions, [&name](const auto& a) { return a.at(0) == name; }) != descriptions.end())
|
||||
write_new = true;
|
||||
return locked.load();
|
||||
}
|
||||
|
||||
fs::path conf_dir;
|
||||
fs::path conf_file;
|
||||
|
||||
vector<string> available_batteries = {"Auto"};
|
||||
|
||||
vector<string> current_boxes;
|
||||
vector<string> preset_list = {"cpu:0:default,mem:0:default,net:0:default,proc:0:default"};
|
||||
int current_preset = -1;
|
||||
|
||||
bool presetsValid(const string& presets) {
|
||||
vector<string> new_presets = {preset_list.at(0)};
|
||||
|
||||
for (int x = 0; const auto& preset : ssplit(presets)) {
|
||||
if (++x > 9) {
|
||||
validError = "Too many presets entered!";
|
||||
return false;
|
||||
}
|
||||
for (int y = 0; const auto& box : ssplit(preset, ',')) {
|
||||
if (++y > 4) {
|
||||
validError = "Too many boxes entered for preset!";
|
||||
return false;
|
||||
}
|
||||
const auto& vals = ssplit(box, ':');
|
||||
if (vals.size() != 3) {
|
||||
validError = "Malformatted preset in config value presets!";
|
||||
return false;
|
||||
}
|
||||
if (not is_in(vals.at(0), "cpu", "mem", "net", "proc", "gpu0", "gpu1", "gpu2", "gpu3", "gpu4", "gpu5")) {
|
||||
validError = "Invalid box name in config value presets!";
|
||||
return false;
|
||||
}
|
||||
if (not is_in(vals.at(1), "0", "1")) {
|
||||
validError = "Invalid position value in config value presets!";
|
||||
return false;
|
||||
}
|
||||
if (not v_contains(valid_graph_symbols_def, vals.at(2))) {
|
||||
validError = "Invalid graph name in config value presets!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
new_presets.push_back(preset);
|
||||
}
|
||||
|
||||
preset_list = std::move(new_presets);
|
||||
return true;
|
||||
}
|
||||
|
||||
//* Apply selected preset
|
||||
bool apply_preset(const string& preset) {
|
||||
string boxes;
|
||||
|
||||
for (const auto& box : ssplit(preset, ',')) {
|
||||
const auto& vals = ssplit(box, ':');
|
||||
boxes += vals.at(0) + ' ';
|
||||
}
|
||||
if (not boxes.empty()) boxes.pop_back();
|
||||
|
||||
auto min_size = Term::get_min_size(boxes);
|
||||
if (Term::width < min_size.at(0) or Term::height < min_size.at(1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& box : ssplit(preset, ',')) {
|
||||
const auto& vals = ssplit(box, ':');
|
||||
if (vals.at(0) == "cpu") {
|
||||
set("cpu_bottom", (vals.at(1) != "0"));
|
||||
} else if (vals.at(0) == "mem") {
|
||||
set("mem_below_net", (vals.at(1) != "0"));
|
||||
} else if (vals.at(0) == "proc") {
|
||||
set("proc_left", (vals.at(1) != "0"));
|
||||
}
|
||||
if (vals.at(0).starts_with("gpu")) {
|
||||
set("graph_symbol_gpu", vals.at(2));
|
||||
} else {
|
||||
set(strings.find("graph_symbol_" + vals.at(0))->first, vals.at(2));
|
||||
}
|
||||
}
|
||||
|
||||
if (set_boxes(boxes)) {
|
||||
set("shown_boxes", boxes);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void lock() {
|
||||
atomic_wait(writelock);
|
||||
locked = true;
|
||||
}
|
||||
|
||||
string validError;
|
||||
|
||||
bool intValid(const std::string_view name, const string& value) {
|
||||
int i_value;
|
||||
try {
|
||||
i_value = stoi(value);
|
||||
}
|
||||
catch (const std::invalid_argument&) {
|
||||
validError = "Invalid numerical value!";
|
||||
return false;
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
validError = "Value out of range!";
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
validError = string{e.what()};
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name == "update_ms" and i_value < 100)
|
||||
validError = "Config value update_ms set too low (<100).";
|
||||
|
||||
else if (name == "update_ms" and i_value > ONE_DAY_MILLIS)
|
||||
validError = fmt::format("Config value update_ms set too high (>{}).", ONE_DAY_MILLIS);
|
||||
|
||||
else
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool validBoxSizes(const string& boxes) {
|
||||
auto min_size = Term::get_min_size(boxes);
|
||||
return (Term::width >= min_size.at(0) and Term::height >= min_size.at(1));
|
||||
}
|
||||
|
||||
bool stringValid(const std::string_view name, const string& value) {
|
||||
if (name == "log_level" and not v_contains(Logger::log_levels, value))
|
||||
validError = "Invalid log_level: " + value;
|
||||
|
||||
else if (name == "graph_symbol" and not v_contains(valid_graph_symbols, value))
|
||||
validError = "Invalid graph symbol identifier: " + value;
|
||||
|
||||
else if (name.starts_with("graph_symbol_") and (value != "default" and not v_contains(valid_graph_symbols, value)))
|
||||
validError = fmt::format("Invalid graph symbol identifier for {}: {}", name, value);
|
||||
|
||||
else if (name == "shown_boxes" and not Global::init_conf) {
|
||||
if (value.empty())
|
||||
validError = "No boxes selected!";
|
||||
else if (not validBoxSizes(value))
|
||||
validError = "Terminal too small to display entered boxes!";
|
||||
else if (not set_boxes(value))
|
||||
validError = "Invalid box name(s) in shown_boxes!";
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef GPU_SUPPORT
|
||||
else if (name == "show_gpu_info" and not v_contains(show_gpu_values, value))
|
||||
validError = "Invalid value for show_gpu_info: " + value;
|
||||
#endif
|
||||
|
||||
else if (name == "presets" and not presetsValid(value))
|
||||
return false;
|
||||
|
||||
else if (name == "cpu_core_map") {
|
||||
const auto maps = ssplit(value);
|
||||
bool all_good = true;
|
||||
for (const auto& map : maps) {
|
||||
const auto map_split = ssplit(map, ':');
|
||||
if (map_split.size() != 2)
|
||||
all_good = false;
|
||||
else if (not isint(map_split.at(0)) or not isint(map_split.at(1)))
|
||||
all_good = false;
|
||||
|
||||
if (not all_good) {
|
||||
validError = "Invalid formatting of cpu_core_map!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (name == "io_graph_speeds") {
|
||||
const auto maps = ssplit(value);
|
||||
bool all_good = true;
|
||||
for (const auto& map : maps) {
|
||||
const auto map_split = ssplit(map, ':');
|
||||
if (map_split.size() != 2)
|
||||
all_good = false;
|
||||
else if (map_split.at(0).empty() or not isint(map_split.at(1)))
|
||||
all_good = false;
|
||||
|
||||
if (not all_good) {
|
||||
validError = "Invalid formatting of io_graph_speeds!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
else
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string getAsString(const std::string_view name) {
|
||||
if (auto it = bools.find(name); it != bools.end())
|
||||
return it->second ? "True" : "False";
|
||||
if (auto it = ints.find(name); it != ints.end())
|
||||
return to_string(it->second);
|
||||
if (auto it = strings.find(name); it != strings.end())
|
||||
return it->second;
|
||||
return "";
|
||||
}
|
||||
|
||||
void flip(const std::string_view name) {
|
||||
if (_locked(name)) {
|
||||
if (boolsTmp.contains(name)) boolsTmp.at(name) = not boolsTmp.at(name);
|
||||
else boolsTmp.insert_or_assign(name, (not bools.at(name)));
|
||||
}
|
||||
else bools.at(name) = not bools.at(name);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
if (not locked) return;
|
||||
atomic_wait(Runner::active);
|
||||
atomic_lock lck(writelock, true);
|
||||
try {
|
||||
if (Proc::shown) {
|
||||
ints.at("selected_pid") = Proc::selected_pid;
|
||||
strings.at("selected_name") = Proc::selected_name;
|
||||
ints.at("proc_start") = Proc::start;
|
||||
ints.at("proc_selected") = Proc::selected;
|
||||
ints.at("selected_depth") = Proc::selected_depth;
|
||||
}
|
||||
|
||||
for (auto& item : stringsTmp) {
|
||||
strings.at(item.first) = item.second;
|
||||
}
|
||||
stringsTmp.clear();
|
||||
|
||||
for (auto& item : intsTmp) {
|
||||
ints.at(item.first) = item.second;
|
||||
}
|
||||
intsTmp.clear();
|
||||
|
||||
for (auto& item : boolsTmp) {
|
||||
bools.at(item.first) = item.second;
|
||||
}
|
||||
boolsTmp.clear();
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
Global::exit_error_msg = "Exception during Config::unlock() : " + string{e.what()};
|
||||
clean_quit(1);
|
||||
}
|
||||
|
||||
locked = false;
|
||||
}
|
||||
|
||||
bool set_boxes(const string& boxes) {
|
||||
auto new_boxes = ssplit(boxes);
|
||||
for (auto& box : new_boxes) {
|
||||
if (not v_contains(valid_boxes, box)) return false;
|
||||
#ifdef GPU_SUPPORT
|
||||
if (box.starts_with("gpu")) {
|
||||
int gpu_num = stoi(box.substr(3)) + 1;
|
||||
if (gpu_num > Gpu::count) return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
current_boxes = std::move(new_boxes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool toggle_box(const string& box) {
|
||||
auto old_boxes = current_boxes;
|
||||
auto box_pos = rng::find(current_boxes, box);
|
||||
if (box_pos == current_boxes.end())
|
||||
current_boxes.push_back(box);
|
||||
else
|
||||
current_boxes.erase(box_pos);
|
||||
|
||||
string new_boxes;
|
||||
if (not current_boxes.empty()) {
|
||||
for (const auto& b : current_boxes) new_boxes += b + ' ';
|
||||
new_boxes.pop_back();
|
||||
}
|
||||
|
||||
auto min_size = Term::get_min_size(new_boxes);
|
||||
|
||||
if (Term::width < min_size.at(0) or Term::height < min_size.at(1)) {
|
||||
current_boxes = old_boxes;
|
||||
return false;
|
||||
}
|
||||
|
||||
Config::set("shown_boxes", new_boxes);
|
||||
return true;
|
||||
}
|
||||
|
||||
void load(const fs::path& conf_file, vector<string>& load_warnings) {
|
||||
std::error_code error;
|
||||
if (conf_file.empty())
|
||||
return;
|
||||
else if (not fs::exists(conf_file, error)) {
|
||||
write_new = true;
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream cread(conf_file);
|
||||
if (cread.good()) {
|
||||
vector<string> valid_names;
|
||||
valid_names.reserve(descriptions.size());
|
||||
for (const auto &n : descriptions)
|
||||
valid_names.push_back(n[0]);
|
||||
if (string v_string; cread.peek() != '#' or (getline(cread, v_string, '\n') and not v_string.contains(Global::Version)))
|
||||
write_new = true;
|
||||
while (not cread.eof()) {
|
||||
cread >> std::ws;
|
||||
if (cread.peek() == '#') {
|
||||
cread.ignore(SSmax, '\n');
|
||||
continue;
|
||||
}
|
||||
string name, value;
|
||||
getline(cread, name, '=');
|
||||
if (name.ends_with(' ')) name = trim(name);
|
||||
if (not v_contains(valid_names, name)) {
|
||||
cread.ignore(SSmax, '\n');
|
||||
continue;
|
||||
}
|
||||
cread >> std::ws;
|
||||
|
||||
if (bools.contains(name)) {
|
||||
cread >> value;
|
||||
if (not isbool(value))
|
||||
load_warnings.push_back("Got an invalid bool value for config name: " + name);
|
||||
else
|
||||
bools.at(name) = stobool(value);
|
||||
}
|
||||
else if (ints.contains(name)) {
|
||||
cread >> value;
|
||||
if (not isint(value))
|
||||
load_warnings.push_back("Got an invalid integer value for config name: " + name);
|
||||
else if (not intValid(name, value)) {
|
||||
load_warnings.push_back(validError);
|
||||
}
|
||||
else
|
||||
ints.at(name) = stoi(value);
|
||||
}
|
||||
else if (strings.contains(name)) {
|
||||
if (cread.peek() == '"') {
|
||||
cread.ignore(1);
|
||||
getline(cread, value, '"');
|
||||
}
|
||||
else cread >> value;
|
||||
|
||||
if (not stringValid(name, value))
|
||||
load_warnings.push_back(validError);
|
||||
else
|
||||
strings.at(name) = value;
|
||||
}
|
||||
|
||||
cread.ignore(SSmax, '\n');
|
||||
}
|
||||
|
||||
if (not load_warnings.empty()) write_new = true;
|
||||
}
|
||||
}
|
||||
|
||||
void write() {
|
||||
if (conf_file.empty() or not write_new) return;
|
||||
Logger::debug("Writing new config file");
|
||||
if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return;
|
||||
std::ofstream cwrite(conf_file, std::ios::trunc);
|
||||
cwrite.imbue(std::locale::classic());
|
||||
if (cwrite.good()) {
|
||||
cwrite << "#? Config file for btop v. " << Global::Version << "\n";
|
||||
for (const auto& [name, description] : descriptions) {
|
||||
cwrite << "\n" << (description.empty() ? "" : description + "\n")
|
||||
<< name << " = ";
|
||||
if (strings.contains(name))
|
||||
cwrite << "\"" << strings.at(name) << "\"";
|
||||
else if (ints.contains(name))
|
||||
cwrite << ints.at(name);
|
||||
else if (bools.contains(name))
|
||||
cwrite << (bools.at(name) ? "True" : "False");
|
||||
cwrite << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr auto get_xdg_state_dir() -> std::optional<fs::path> {
|
||||
std::optional<fs::path> xdg_state_home;
|
||||
|
||||
{
|
||||
const auto* xdg_state_home_ptr = std::getenv("XDG_STATE_HOME");
|
||||
if (xdg_state_home_ptr != nullptr) {
|
||||
xdg_state_home = std::make_optional(fs::path(xdg_state_home_ptr));
|
||||
} else {
|
||||
const auto* home_ptr = std::getenv("HOME");
|
||||
if (home_ptr != nullptr) {
|
||||
xdg_state_home = std::make_optional(fs::path(home_ptr) / ".local" / "state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xdg_state_home.has_value()) {
|
||||
std::error_code err;
|
||||
fs::create_directories(xdg_state_home.value(), err);
|
||||
if (err) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return xdg_state_home;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto get_log_file() -> std::optional<fs::path> {
|
||||
return get_xdg_state_dir().transform([](auto&& state_home) -> auto { return state_home / "btop.log"; });
|
||||
}
|
||||
}
|
||||
135
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/btop_config.hpp
vendored
Normal file
135
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/btop_config.hpp
vendored
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
//* Functions and variables for reading and writing the btop config file
|
||||
namespace Config {
|
||||
|
||||
extern std::filesystem::path conf_dir;
|
||||
extern std::filesystem::path conf_file;
|
||||
|
||||
extern std::unordered_map<std::string_view, string> strings;
|
||||
extern std::unordered_map<std::string_view, string> stringsTmp;
|
||||
extern std::unordered_map<std::string_view, bool> bools;
|
||||
extern std::unordered_map<std::string_view, bool> boolsTmp;
|
||||
extern std::unordered_map<std::string_view, int> ints;
|
||||
extern std::unordered_map<std::string_view, int> intsTmp;
|
||||
|
||||
const vector<string> valid_graph_symbols = { "braille", "block", "tty" };
|
||||
const vector<string> valid_graph_symbols_def = { "default", "braille", "block", "tty" };
|
||||
const vector<string> valid_boxes = {
|
||||
"cpu", "mem", "net", "proc"
|
||||
#ifdef GPU_SUPPORT
|
||||
,"gpu0", "gpu1", "gpu2", "gpu3", "gpu4", "gpu5"
|
||||
#endif
|
||||
};
|
||||
const vector<string> temp_scales = { "celsius", "fahrenheit", "kelvin", "rankine" };
|
||||
#ifdef __linux__
|
||||
const vector<string> freq_modes = { "first", "range", "lowest", "highest", "average" };
|
||||
#endif
|
||||
#ifdef GPU_SUPPORT
|
||||
const vector<string> show_gpu_values = { "Auto", "On", "Off" };
|
||||
#endif
|
||||
const vector<string> base_10_bitrate_values = { "Auto", "True", "False" };
|
||||
extern vector<string> current_boxes;
|
||||
extern vector<string> preset_list;
|
||||
extern vector<string> available_batteries;
|
||||
extern int current_preset;
|
||||
|
||||
constexpr int ONE_DAY_MILLIS = 1000 * 60 * 60 * 24;
|
||||
|
||||
[[nodiscard]] std::optional<std::filesystem::path> get_config_dir() noexcept;
|
||||
|
||||
//* Check if string only contains space separated valid names for boxes and set current_boxes
|
||||
bool set_boxes(const string& boxes);
|
||||
|
||||
bool validBoxSizes(const string& boxes);
|
||||
|
||||
//* Toggle box and update config string shown_boxes
|
||||
bool toggle_box(const string& box);
|
||||
|
||||
//* Parse and setup config value presets
|
||||
bool presetsValid(const string& presets);
|
||||
|
||||
//* Apply selected preset
|
||||
bool apply_preset(const string& preset);
|
||||
|
||||
bool _locked(const std::string_view name);
|
||||
|
||||
//* Return bool for config key <name>
|
||||
inline bool getB(const std::string_view name) { return bools.at(name); }
|
||||
|
||||
//* Return integer for config key <name>
|
||||
inline const int& getI(const std::string_view name) { return ints.at(name); }
|
||||
|
||||
//* Return string for config key <name>
|
||||
inline const string& getS(const std::string_view name) { return strings.at(name); }
|
||||
|
||||
string getAsString(const std::string_view name);
|
||||
|
||||
extern string validError;
|
||||
|
||||
bool intValid(const std::string_view name, const string& value);
|
||||
bool stringValid(const std::string_view name, const string& value);
|
||||
|
||||
//* Set config key <name> to bool <value>
|
||||
inline void set(const std::string_view name, bool value) {
|
||||
if (_locked(name)) boolsTmp.insert_or_assign(name, value);
|
||||
else bools.at(name) = value;
|
||||
}
|
||||
|
||||
//* Set config key <name> to int <value>
|
||||
inline void set(const std::string_view name, const int value) {
|
||||
if (_locked(name)) intsTmp.insert_or_assign(name, value);
|
||||
else ints.at(name) = value;
|
||||
}
|
||||
|
||||
//* Set config key <name> to string <value>
|
||||
inline void set(const std::string_view name, const string& value) {
|
||||
if (_locked(name)) stringsTmp.insert_or_assign(name, value);
|
||||
else strings.at(name) = value;
|
||||
}
|
||||
|
||||
//* Flip config key bool <name>
|
||||
void flip(const std::string_view name);
|
||||
|
||||
//* Lock config and cache changes until unlocked
|
||||
void lock();
|
||||
|
||||
//* Unlock config and write any cached values to config
|
||||
void unlock();
|
||||
|
||||
//* Load the config file from disk
|
||||
void load(const std::filesystem::path& conf_file, vector<string>& load_warnings);
|
||||
|
||||
//* Write the config file to disk
|
||||
void write();
|
||||
|
||||
auto get_log_file() -> std::optional<std::filesystem::path>;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,141 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using std::array;
|
||||
using std::deque;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace Symbols {
|
||||
const string h_line = "─";
|
||||
const string v_line = "│";
|
||||
const string dotted_v_line = "╎";
|
||||
const string left_up = "┌";
|
||||
const string right_up = "┐";
|
||||
const string left_down = "└";
|
||||
const string right_down = "┘";
|
||||
const string round_left_up = "╭";
|
||||
const string round_right_up = "╮";
|
||||
const string round_left_down = "╰";
|
||||
const string round_right_down = "╯";
|
||||
const string title_left_down = "┘";
|
||||
const string title_right_down = "└";
|
||||
const string title_left = "┐";
|
||||
const string title_right = "┌";
|
||||
const string div_right = "┤";
|
||||
const string div_left = "├";
|
||||
const string div_up = "┬";
|
||||
const string div_down = "┴";
|
||||
|
||||
|
||||
const string up = "↑";
|
||||
const string down = "↓";
|
||||
const string left = "←";
|
||||
const string right = "→";
|
||||
const string enter = "↵";
|
||||
}
|
||||
|
||||
namespace Draw {
|
||||
|
||||
//* Generate if needed and return the btop++ banner
|
||||
string banner_gen(int y=0, int x=0, bool centered=false, bool redraw=false);
|
||||
|
||||
//* An editable text field
|
||||
class TextEdit {
|
||||
size_t pos{};
|
||||
size_t upos{};
|
||||
bool numeric = false;
|
||||
public:
|
||||
string text;
|
||||
TextEdit();
|
||||
explicit TextEdit(string text, bool numeric=false);
|
||||
bool command(const std::string_view key);
|
||||
string operator()(const size_t limit=0);
|
||||
void clear();
|
||||
};
|
||||
|
||||
//* Create a box and return as a string
|
||||
string createBox(
|
||||
const int x, const int y, const int width, const int height, string line_color = "", bool fill = false,
|
||||
const std::string_view title = "", const std::string_view title2 = "", const int num = 0
|
||||
);
|
||||
|
||||
bool update_clock(bool force = false);
|
||||
|
||||
//* Class holding a percentage meter
|
||||
class Meter {
|
||||
int width;
|
||||
string color_gradient;
|
||||
bool invert;
|
||||
array<string, 101> cache;
|
||||
public:
|
||||
Meter();
|
||||
Meter(const int width, string color_gradient, bool invert = false);
|
||||
|
||||
//* Return a string representation of the meter with given value
|
||||
string operator()(int value);
|
||||
};
|
||||
|
||||
//* Class holding a percentage graph
|
||||
class Graph {
|
||||
int width, height;
|
||||
string color_gradient;
|
||||
string out, symbol = "default";
|
||||
bool invert, no_zero;
|
||||
long long offset;
|
||||
long long last = 0, max_value = 0;
|
||||
bool current = true, tty_mode = false;
|
||||
std::unordered_map<bool, vector<string>> graphs = { {true, {}}, {false, {}}};
|
||||
|
||||
//* Create two representations of the graph to switch between to represent two values for each braille character
|
||||
void _create(const deque<long long>& data, int data_offset);
|
||||
|
||||
public:
|
||||
Graph();
|
||||
Graph(int width, int height,
|
||||
const string& color_gradient,
|
||||
const deque<long long>& data,
|
||||
const string& symbol="default",
|
||||
bool invert=false, bool no_zero=false,
|
||||
long long max_value=0, long long offset=0);
|
||||
|
||||
//* Add last value from back of <data> and return string representation of graph
|
||||
string& operator()(const deque<long long>& data, bool data_same=false);
|
||||
|
||||
//* Return string representation of graph
|
||||
string& operator()();
|
||||
};
|
||||
|
||||
//* Calculate sizes of boxes, draw outlines and save to enabled boxes namespaces
|
||||
void calcSizes();
|
||||
}
|
||||
|
||||
namespace Proc {
|
||||
extern Draw::TextEdit filter;
|
||||
extern std::unordered_map<size_t, Draw::Graph> p_graphs;
|
||||
extern std::unordered_map<size_t, int> p_counters;
|
||||
}
|
||||
|
|
@ -0,0 +1,542 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <fmt/format.h>
|
||||
#include <signal.h>
|
||||
#include <sys/select.h>
|
||||
#include <utility>
|
||||
|
||||
#include "btop_input.hpp"
|
||||
#include "btop_tools.hpp"
|
||||
#include "btop_config.hpp"
|
||||
#include "btop_shared.hpp"
|
||||
#include "btop_menu.hpp"
|
||||
#include "btop_draw.hpp"
|
||||
|
||||
using namespace Tools;
|
||||
using namespace std::literals; // for operator""s
|
||||
namespace rng = std::ranges;
|
||||
|
||||
namespace Input {
|
||||
|
||||
//* Map for translating key codes to readable values
|
||||
const std::unordered_map<string, string> Key_escapes = {
|
||||
{"\033", "escape"},
|
||||
{"\x12", "ctrl_r"},
|
||||
{"\n", "enter"},
|
||||
{" ", "space"},
|
||||
{"\x7f", "backspace"},
|
||||
{"\x08", "backspace"},
|
||||
{"[A", "up"},
|
||||
{"OA", "up"},
|
||||
{"[B", "down"},
|
||||
{"OB", "down"},
|
||||
{"[D", "left"},
|
||||
{"OD", "left"},
|
||||
{"[C", "right"},
|
||||
{"OC", "right"},
|
||||
{"[2~", "insert"},
|
||||
{"[4h", "insert"},
|
||||
{"[3~", "delete"},
|
||||
{"[P", "delete"},
|
||||
{"[H", "home"},
|
||||
{"[1~", "home"},
|
||||
{"[F", "end"},
|
||||
{"[4~", "end"},
|
||||
{"[5~", "page_up"},
|
||||
{"[6~", "page_down"},
|
||||
{"\t", "tab"},
|
||||
{"[Z", "shift_tab"},
|
||||
{"OP", "f1"},
|
||||
{"OQ", "f2"},
|
||||
{"OR", "f3"},
|
||||
{"OS", "f4"},
|
||||
{"[15~", "f5"},
|
||||
{"[17~", "f6"},
|
||||
{"[18~", "f7"},
|
||||
{"[19~", "f8"},
|
||||
{"[20~", "f9"},
|
||||
{"[21~", "f10"},
|
||||
{"[23~", "f11"},
|
||||
{"[24~", "f12"}
|
||||
};
|
||||
|
||||
sigset_t signal_mask;
|
||||
std::atomic<bool> polling (false);
|
||||
array<int, 2> mouse_pos;
|
||||
std::unordered_map<string, Mouse_loc> mouse_mappings;
|
||||
|
||||
deque<string> history(50, "");
|
||||
string old_filter;
|
||||
string input;
|
||||
|
||||
bool poll(const uint64_t timeout) {
|
||||
atomic_lock lck(polling);
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
struct timespec wait;
|
||||
struct timespec *waitptr = nullptr;
|
||||
|
||||
if(timeout != std::numeric_limits<uint64_t>::max()) {
|
||||
wait.tv_sec = timeout / 1000;
|
||||
wait.tv_nsec = (timeout % 1000) * 1000000;
|
||||
waitptr = &wait;
|
||||
}
|
||||
|
||||
if(pselect(STDIN_FILENO + 1, &fds, nullptr, nullptr, waitptr, &signal_mask) > 0) {
|
||||
input.clear();
|
||||
char buf[1024];
|
||||
ssize_t count = 0;
|
||||
while((count = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
|
||||
input.append(std::string_view(buf, count));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string get() {
|
||||
string key = input;
|
||||
if (not key.empty()) {
|
||||
//? Remove escape code prefix if present
|
||||
if (key.length() > 1 and key.at(0) == Fx::e.at(0)) {
|
||||
key.erase(0, 1);
|
||||
}
|
||||
//? Detect if input is an mouse event
|
||||
if (key.starts_with("[<")) {
|
||||
std::string_view key_view = key;
|
||||
string mouse_event;
|
||||
if (key_view.starts_with("[<0;") and key_view.find('M') != std::string_view::npos) {
|
||||
mouse_event = "mouse_click";
|
||||
key_view.remove_prefix(4);
|
||||
}
|
||||
// else if (key_view.starts_with("[<0;") and key_view.ends_with('m')) {
|
||||
// mouse_event = "mouse_release";
|
||||
// key_view.remove_prefix(4);
|
||||
// }
|
||||
else if (key_view.starts_with("[<64;")) {
|
||||
mouse_event = "mouse_scroll_up";
|
||||
key_view.remove_prefix(5);
|
||||
}
|
||||
else if (key_view.starts_with("[<65;")) {
|
||||
mouse_event = "mouse_scroll_down";
|
||||
key_view.remove_prefix(5);
|
||||
}
|
||||
else
|
||||
key.clear();
|
||||
|
||||
if (Config::getB("proc_filtering")) {
|
||||
if (mouse_event == "mouse_click") return mouse_event;
|
||||
else return "";
|
||||
}
|
||||
|
||||
//? Get column and line position of mouse and check for any actions mapped to current position
|
||||
if (not key.empty()) {
|
||||
try {
|
||||
const auto delim = key_view.find(';');
|
||||
mouse_pos[0] = stoi((string)key_view.substr(0, delim));
|
||||
mouse_pos[1] = stoi((string)key_view.substr(delim + 1, key_view.find('M', delim)));
|
||||
}
|
||||
catch (const std::invalid_argument&) { mouse_event.clear(); }
|
||||
catch (const std::out_of_range&) { mouse_event.clear(); }
|
||||
|
||||
key = mouse_event;
|
||||
|
||||
if (key == "mouse_click") {
|
||||
const auto& [col, line] = mouse_pos;
|
||||
|
||||
for (const auto& [mapped_key, pos] : (Menu::active ? Menu::mouse_mappings : mouse_mappings)) {
|
||||
if (col >= pos.col and col < pos.col + pos.width and line >= pos.line and line < pos.line + pos.height) {
|
||||
key = mapped_key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (auto it = Key_escapes.find(key); it != Key_escapes.end())
|
||||
key = it->second;
|
||||
else if (ulen(key) > 1)
|
||||
key.clear();
|
||||
|
||||
if (not key.empty()) {
|
||||
history.push_back(key);
|
||||
history.pop_front();
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
string wait() {
|
||||
while(not poll(std::numeric_limits<uint64_t>::max())) {}
|
||||
return get();
|
||||
}
|
||||
|
||||
void interrupt() {
|
||||
kill(getpid(), SIGUSR1);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
// do not need it, actually
|
||||
}
|
||||
|
||||
void process(const std::string_view key) {
|
||||
if (key.empty()) return;
|
||||
try {
|
||||
auto filtering = Config::getB("proc_filtering");
|
||||
auto vim_keys = Config::getB("vim_keys");
|
||||
auto help_key = (vim_keys ? "H" : "h");
|
||||
auto kill_key = (vim_keys ? "K" : "k");
|
||||
//? Global input actions
|
||||
if (not filtering) {
|
||||
bool keep_going = false;
|
||||
if (key == "q") {
|
||||
clean_quit(0);
|
||||
}
|
||||
else if (is_in(key, "escape", "m")) {
|
||||
Menu::show(Menu::Menus::Main);
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "f1", "?", help_key)) {
|
||||
Menu::show(Menu::Menus::Help);
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "f2", "o")) {
|
||||
Menu::show(Menu::Menus::Options);
|
||||
return;
|
||||
}
|
||||
else if (key.size() == 1 and isint(key)) {
|
||||
auto intKey = std::atoi(key.data());
|
||||
// AltData: 1=net, 2=proc,其他屏蔽
|
||||
if (intKey != 1 and intKey != 2)
|
||||
return;
|
||||
// 映射: 1->net(3), 2->proc(4)
|
||||
static const array<string, 3> altBoxes = {"", "net", "proc"};
|
||||
atomic_wait(Runner::active);
|
||||
|
||||
if (not Config::toggle_box(altBoxes.at(intKey))) {
|
||||
Menu::show(Menu::Menus::SizeError);
|
||||
return;
|
||||
}
|
||||
Config::current_preset = -1;
|
||||
Draw::calcSizes();
|
||||
Runner::run("all", false, true);
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "p", "P") and Config::preset_list.size() > 1) {
|
||||
const auto old_preset = Config::current_preset;
|
||||
if (key == "p") {
|
||||
if (++Config::current_preset >= (int)Config::preset_list.size()) Config::current_preset = 0;
|
||||
}
|
||||
else {
|
||||
if (--Config::current_preset < 0) Config::current_preset = Config::preset_list.size() - 1;
|
||||
}
|
||||
atomic_wait(Runner::active);
|
||||
if (not Config::apply_preset(Config::preset_list.at(Config::current_preset))) {
|
||||
Menu::show(Menu::Menus::SizeError);
|
||||
Config::current_preset = old_preset;
|
||||
return;
|
||||
}
|
||||
Draw::calcSizes();
|
||||
Runner::run("all", false, true);
|
||||
return;
|
||||
} else if (is_in(key, "ctrl_r")) {
|
||||
kill(getpid(), SIGUSR2);
|
||||
return;
|
||||
} else
|
||||
keep_going = true;
|
||||
|
||||
if (not keep_going) return;
|
||||
}
|
||||
|
||||
//? Input actions for proc box
|
||||
if (Proc::shown) {
|
||||
bool keep_going = false;
|
||||
bool no_update = true;
|
||||
bool redraw = true;
|
||||
if (filtering) {
|
||||
if (key == "enter" or key == "down") {
|
||||
Config::set("proc_filter", Proc::filter.text);
|
||||
Config::set("proc_filtering", false);
|
||||
old_filter.clear();
|
||||
if(key == "down"){
|
||||
Config::unlock();
|
||||
Config::lock();
|
||||
process("down");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (key == "escape" or key == "mouse_click") {
|
||||
Config::set("proc_filter", old_filter);
|
||||
Config::set("proc_filtering", false);
|
||||
old_filter.clear();
|
||||
}
|
||||
else if (Proc::filter.command(key)) {
|
||||
if (Config::getS("proc_filter") != Proc::filter.text)
|
||||
Config::set("proc_filter", Proc::filter.text);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
else if (key == "left" or (vim_keys and key == "h")) {
|
||||
int cur_i = v_index(Proc::sort_vector, Config::getS("proc_sorting"));
|
||||
if (--cur_i < 0)
|
||||
cur_i = Proc::sort_vector.size() - 1;
|
||||
Config::set("proc_sorting", Proc::sort_vector.at(cur_i));
|
||||
}
|
||||
else if (key == "right" or (vim_keys and key == "l")) {
|
||||
int cur_i = v_index(Proc::sort_vector, Config::getS("proc_sorting"));
|
||||
if (std::cmp_greater(++cur_i, Proc::sort_vector.size() - 1))
|
||||
cur_i = 0;
|
||||
Config::set("proc_sorting", Proc::sort_vector.at(cur_i));
|
||||
}
|
||||
else if (is_in(key, "f", "/")) {
|
||||
Config::flip("proc_filtering");
|
||||
Proc::filter = Draw::TextEdit{Config::getS("proc_filter")};
|
||||
old_filter = Proc::filter.text;
|
||||
}
|
||||
else if (key == "e") {
|
||||
Config::flip("proc_tree");
|
||||
no_update = false;
|
||||
}
|
||||
else if (is_in(key, "F")) {
|
||||
Config::flip("pause_proc_list");
|
||||
redraw = true;
|
||||
}
|
||||
else if (key == "r")
|
||||
Config::flip("proc_reversed");
|
||||
|
||||
else if (key == "c")
|
||||
Config::flip("proc_per_core");
|
||||
|
||||
else if (key == "%")
|
||||
Config::flip("proc_mem_bytes");
|
||||
|
||||
else if (key == "delete" and not Config::getS("proc_filter").empty())
|
||||
Config::set("proc_filter", ""s);
|
||||
|
||||
else if (key.starts_with("mouse_")) {
|
||||
redraw = false;
|
||||
const auto& [col, line] = mouse_pos;
|
||||
const int y = (Config::getB("show_detailed") ? Proc::y + 8 : Proc::y);
|
||||
const int height = (Config::getB("show_detailed") ? Proc::height - 8 : Proc::height);
|
||||
if (col >= Proc::x + 1 and col < Proc::x + Proc::width and line >= y + 1 and line < y + height - 1) {
|
||||
if (key == "mouse_click") {
|
||||
if (col < Proc::x + Proc::width - 2) {
|
||||
const auto& current_selection = Config::getI("proc_selected");
|
||||
if (current_selection == line - y - 1) {
|
||||
redraw = true;
|
||||
if (Config::getB("proc_tree")) {
|
||||
const int x_pos = col - Proc::x;
|
||||
const int offset = Config::getI("selected_depth") * 3;
|
||||
if (x_pos > offset and x_pos < 4 + offset) {
|
||||
process("space");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// AltData: disable enter-triggered detail toggle
|
||||
return;
|
||||
}
|
||||
else if (current_selection == 0 or line - y - 1 == 0)
|
||||
redraw = true;
|
||||
Config::set("proc_selected", line - y - 1);
|
||||
}
|
||||
else if (line == y + 1) {
|
||||
if (Proc::selection("page_up") == -1) return;
|
||||
}
|
||||
else if (line == y + height - 2) {
|
||||
if (Proc::selection("page_down") == -1) return;
|
||||
}
|
||||
else if (Proc::selection("mousey" + to_string(line - y - 2)) == -1)
|
||||
return;
|
||||
}
|
||||
else
|
||||
goto proc_mouse_scroll;
|
||||
}
|
||||
else if (key == "mouse_click" and Config::getI("proc_selected") > 0) {
|
||||
Config::set("proc_selected", 0);
|
||||
redraw = true;
|
||||
}
|
||||
else
|
||||
keep_going = true;
|
||||
}
|
||||
else if (key == "enter") {
|
||||
// AltData: disable enter-triggered detail toggle
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "+", "-", "space", "u") and Config::getB("proc_tree") and Config::getI("proc_selected") > 0) {
|
||||
atomic_wait(Runner::active);
|
||||
auto& pid = Config::getI("selected_pid");
|
||||
if (key == "+" or key == "space") Proc::expand = pid;
|
||||
if (key == "-" or key == "space") Proc::collapse = pid;
|
||||
if (key == "u") Proc::toggle_children = pid;
|
||||
no_update = false;
|
||||
}
|
||||
else if (is_in(key, "t", kill_key) and (Config::getB("show_detailed") or Config::getI("selected_pid") > 0)) {
|
||||
atomic_wait(Runner::active);
|
||||
if (Config::getB("show_detailed") and Config::getI("proc_selected") == 0 and Proc::detailed.status == "Dead") return;
|
||||
Menu::show(Menu::Menus::SignalSend, (key == "t" ? SIGTERM : SIGKILL));
|
||||
return;
|
||||
}
|
||||
else if (key == "s" and (Config::getB("show_detailed") or Config::getI("selected_pid") > 0)) {
|
||||
atomic_wait(Runner::active);
|
||||
if (Config::getB("show_detailed") and Config::getI("proc_selected") == 0 and Proc::detailed.status == "Dead") return;
|
||||
Menu::show(Menu::Menus::SignalChoose);
|
||||
return;
|
||||
}
|
||||
else if (key == "N" and (Config::getB("show_detailed") or Config::getI("selected_pid") > 0)) {
|
||||
atomic_wait(Runner::active);
|
||||
if (Config::getB("show_detailed") and Config::getI("proc_selected") == 0 and Proc::detailed.status == "Dead") return;
|
||||
Menu::show(Menu::Menus::Renice);
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "up", "down", "page_up", "page_down", "home", "end") or (vim_keys and is_in(key, "j", "k", "g", "G"))) {
|
||||
proc_mouse_scroll:
|
||||
redraw = false;
|
||||
auto old_selected = Config::getI("proc_selected");
|
||||
auto new_selected = Proc::selection(key);
|
||||
if (new_selected == -1)
|
||||
return;
|
||||
else if (old_selected != new_selected and (old_selected == 0 or new_selected == 0))
|
||||
redraw = true;
|
||||
}
|
||||
else keep_going = true;
|
||||
|
||||
if (not keep_going) {
|
||||
Runner::run("proc", no_update, redraw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//? Input actions for cpu box
|
||||
if (Cpu::shown) {
|
||||
bool keep_going = false;
|
||||
bool no_update = true;
|
||||
bool redraw = true;
|
||||
static uint64_t last_press = 0;
|
||||
|
||||
if (key == "+" and Config::getI("update_ms") <= 86399900) {
|
||||
int add = (Config::getI("update_ms") <= 86399000 and last_press >= time_ms() - 200
|
||||
and rng::all_of(Input::history, [](const auto& str){ return str == "+"; })
|
||||
? 1000 : 100);
|
||||
Config::set("update_ms", Config::getI("update_ms") + add);
|
||||
last_press = time_ms();
|
||||
redraw = true;
|
||||
}
|
||||
else if (key == "-" and Config::getI("update_ms") >= 200) {
|
||||
int sub = (Config::getI("update_ms") >= 2000 and last_press >= time_ms() - 200
|
||||
and rng::all_of(Input::history, [](const auto& str){ return str == "-"; })
|
||||
? 1000 : 100);
|
||||
Config::set("update_ms", Config::getI("update_ms") - sub);
|
||||
last_press = time_ms();
|
||||
redraw = true;
|
||||
}
|
||||
else keep_going = true;
|
||||
|
||||
if (not keep_going) {
|
||||
Runner::run("cpu", no_update, redraw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//? Input actions for mem box
|
||||
if (Mem::shown) {
|
||||
bool keep_going = false;
|
||||
bool no_update = true;
|
||||
bool redraw = true;
|
||||
|
||||
if (key == "i") {
|
||||
Config::flip("io_mode");
|
||||
}
|
||||
else if (key == "d") {
|
||||
Config::flip("show_disks");
|
||||
no_update = false;
|
||||
Draw::calcSizes();
|
||||
}
|
||||
else keep_going = true;
|
||||
|
||||
if (not keep_going) {
|
||||
Runner::run("mem", no_update, redraw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//? Input actions for net box
|
||||
if (Net::shown) {
|
||||
bool keep_going = false;
|
||||
bool no_update = true;
|
||||
bool redraw = true;
|
||||
|
||||
if (is_in(key, "b", "n")) {
|
||||
atomic_wait(Runner::active);
|
||||
int c_index = v_index(Net::interfaces, Net::selected_iface);
|
||||
if (c_index != (int)Net::interfaces.size()) {
|
||||
if (key == "b") {
|
||||
if (--c_index < 0) c_index = Net::interfaces.size() - 1;
|
||||
}
|
||||
else if (key == "n") {
|
||||
if (++c_index == (int)Net::interfaces.size()) c_index = 0;
|
||||
}
|
||||
Net::selected_iface = Net::interfaces.at(c_index);
|
||||
Net::rescale = true;
|
||||
}
|
||||
}
|
||||
else if (key == "y") {
|
||||
Config::flip("net_sync");
|
||||
Net::rescale = true;
|
||||
}
|
||||
else if (key == "a") {
|
||||
Config::flip("net_auto");
|
||||
Net::rescale = true;
|
||||
}
|
||||
else if (key == "z") {
|
||||
atomic_wait(Runner::active);
|
||||
auto& ndev = Net::current_net.at(Net::selected_iface);
|
||||
if (ndev.stat.at("download").offset + ndev.stat.at("upload").offset > 0) {
|
||||
ndev.stat.at("download").offset = 0;
|
||||
ndev.stat.at("upload").offset = 0;
|
||||
}
|
||||
else {
|
||||
ndev.stat.at("download").offset = ndev.stat.at("download").last + ndev.stat.at("download").rollover;
|
||||
ndev.stat.at("upload").offset = ndev.stat.at("upload").last + ndev.stat.at("upload").rollover;
|
||||
}
|
||||
no_update = false;
|
||||
}
|
||||
else keep_going = true;
|
||||
|
||||
if (not keep_going) {
|
||||
Runner::run("net", no_update, redraw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (const std::exception& e) {
|
||||
throw std::runtime_error { fmt::format(R"(Input::process("{}"))", e.what()) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::deque;
|
||||
using std::string;
|
||||
|
||||
/* The input functions rely on the following termios parameters being set:
|
||||
Non-canonical mode (c_lflags & ~(ICANON))
|
||||
VMIN and VTIME (c_cc) set to 0
|
||||
These will automatically be set when running Term::init() from btop_tools.cpp
|
||||
*/
|
||||
|
||||
//* Functions and variables for handling keyboard and mouse input
|
||||
namespace Input {
|
||||
|
||||
struct Mouse_loc {
|
||||
int line, col, height, width;
|
||||
};
|
||||
|
||||
//? line, col, height, width
|
||||
extern std::unordered_map<string, Mouse_loc> mouse_mappings;
|
||||
|
||||
//* Signal mask used during polling read
|
||||
extern sigset_t signal_mask;
|
||||
|
||||
extern atomic<bool> polling;
|
||||
|
||||
//* Mouse column and line position
|
||||
extern array<int, 2> mouse_pos;
|
||||
|
||||
//* Last entered key
|
||||
extern deque<string> history;
|
||||
|
||||
//* Poll keyboard & mouse input for <timeout> ms and return input availability as a bool
|
||||
bool poll(const uint64_t timeout=0);
|
||||
|
||||
//* Get a key or mouse action from input
|
||||
string get();
|
||||
|
||||
//* Wait until input is available and return key
|
||||
string wait();
|
||||
|
||||
//* Interrupt poll/wait
|
||||
void interrupt();
|
||||
|
||||
//* Clears last entered key
|
||||
void clear();
|
||||
|
||||
//* Process actions for input <key>
|
||||
void process(const std::string_view key);
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,99 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "btop_input.hpp"
|
||||
|
||||
using std::atomic;
|
||||
using std::bitset;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace Menu {
|
||||
|
||||
extern atomic<bool> active;
|
||||
extern string output;
|
||||
extern int signalToSend;
|
||||
extern bool redraw;
|
||||
|
||||
//? line, col, height, width
|
||||
extern std::unordered_map<string, Input::Mouse_loc> mouse_mappings;
|
||||
|
||||
//* Creates a message box centered on screen
|
||||
//? Height of box is determined by size of content vector
|
||||
//? Boxtypes: 0 = OK button | 1 = YES and NO with YES selected | 2 = Same as 1 but with NO selected
|
||||
//? Strings in content vector is not checked for box width overflow
|
||||
class msgBox {
|
||||
string box_contents, button_left, button_right;
|
||||
int height{};
|
||||
int width{};
|
||||
int boxtype{};
|
||||
int selected{};
|
||||
int x{};
|
||||
int y{};
|
||||
public:
|
||||
enum BoxTypes { OK, YES_NO, NO_YES };
|
||||
enum msgReturn {
|
||||
Invalid,
|
||||
Ok_Yes,
|
||||
No_Esc,
|
||||
Select
|
||||
};
|
||||
msgBox();
|
||||
msgBox(int width, int boxtype, const vector<string>& content, std::string_view title);
|
||||
|
||||
//? Draw and return box as a string
|
||||
string operator()();
|
||||
|
||||
//? Process input and returns value from enum Ret
|
||||
int input(const string& key);
|
||||
|
||||
//? Clears content vector and private strings
|
||||
void clear();
|
||||
int getX() const { return x; }
|
||||
int getY() const { return y; }
|
||||
};
|
||||
|
||||
extern bitset<8> menuMask;
|
||||
|
||||
//* Enum for functions in vector menuFuncs
|
||||
enum Menus {
|
||||
SizeError,
|
||||
SignalChoose,
|
||||
SignalSend,
|
||||
SignalReturn,
|
||||
Options,
|
||||
Help,
|
||||
Renice,
|
||||
Main
|
||||
};
|
||||
|
||||
//* Handles redirection of input for menu functions and handles return codes
|
||||
void process(const std::string_view key = "");
|
||||
|
||||
//* Show a menu from enum Menu::Menus
|
||||
void show(int menu, int signal=-1);
|
||||
|
||||
}
|
||||
292
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/btop_shared.cpp
vendored
Normal file
292
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/btop_shared.cpp
vendored
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <ranges>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "btop_config.hpp"
|
||||
#include "btop_shared.hpp"
|
||||
#include "btop_tools.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace rng = std::ranges;
|
||||
using namespace Tools;
|
||||
|
||||
namespace Cpu {
|
||||
std::optional<std::string> container_engine;
|
||||
|
||||
string trim_name(string name) {
|
||||
auto name_vec = ssplit(name);
|
||||
|
||||
if ((name.contains("Xeon") or v_contains(name_vec, "Duo"s)) and v_contains(name_vec, "CPU"s)) {
|
||||
auto cpu_pos = v_index(name_vec, "CPU"s);
|
||||
if (cpu_pos < name_vec.size() - 1 and not name_vec.at(cpu_pos + 1).ends_with(')'))
|
||||
name = name_vec.at(cpu_pos + 1);
|
||||
else
|
||||
name.clear();
|
||||
} else if (v_contains(name_vec, "Ryzen"s)) {
|
||||
auto ryz_pos = v_index(name_vec, "Ryzen"s);
|
||||
name = "Ryzen";
|
||||
int tokens = 0;
|
||||
for (auto i = ryz_pos + 1; i < name_vec.size() && tokens < 2; i++) {
|
||||
const std::string& p = name_vec.at(i);
|
||||
if (p != "AI" && p != "PRO" && p != "H" && p != "HX")
|
||||
tokens++;
|
||||
name += " " + p;
|
||||
}
|
||||
} else if (name.contains("Intel") and v_contains(name_vec, "CPU"s)) {
|
||||
auto cpu_pos = v_index(name_vec, "CPU"s);
|
||||
if (cpu_pos < name_vec.size() - 1 and not name_vec.at(cpu_pos + 1).ends_with(')') and name_vec.at(cpu_pos + 1) != "@")
|
||||
name = name_vec.at(cpu_pos + 1);
|
||||
else
|
||||
name.clear();
|
||||
} else
|
||||
name.clear();
|
||||
|
||||
if (name.empty() and not name_vec.empty()) {
|
||||
for (const auto &n : name_vec) {
|
||||
if (n == "@") break;
|
||||
name += n + ' ';
|
||||
}
|
||||
name.pop_back();
|
||||
for (const auto& replace : {"Processor", "CPU", "(R)", "(TM)", "Intel", "AMD", "Apple", "Core"}) {
|
||||
name = s_replace(name, replace, "");
|
||||
name = s_replace(name, " ", " ");
|
||||
}
|
||||
name = trim(name);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GPU_SUPPORT
|
||||
namespace Gpu {
|
||||
vector<string> gpu_names;
|
||||
vector<int> gpu_b_height_offsets;
|
||||
std::unordered_map<string, deque<long long>> shared_gpu_percent = {
|
||||
{"gpu-average", {}},
|
||||
{"gpu-vram-total", {}},
|
||||
{"gpu-pwr-total", {}},
|
||||
};
|
||||
long long gpu_pwr_total_max = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Proc {
|
||||
bool set_priority(pid_t pid, int priority) {
|
||||
if (setpriority(PRIO_PROCESS, pid, priority) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void proc_sorter(vector<proc_info>& proc_vec, const string& sorting, bool reverse, bool tree) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(proc_vec, rng::less{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(proc_vec, rng::less{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(proc_vec, rng::less{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(proc_vec, rng::less{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(proc_vec, rng::less{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
|
||||
//* When sorting with "cpu lazy" push processes over threshold cpu usage to the front regardless of cumulative usage
|
||||
if (not tree and not reverse and sorting == "cpu lazy") {
|
||||
double max = 10.0, target = 30.0;
|
||||
for (size_t i = 0, x = 0, offset = 0; i < proc_vec.size(); i++) {
|
||||
if (i <= 5 and proc_vec.at(i).cpu_p > max)
|
||||
max = proc_vec.at(i).cpu_p;
|
||||
else if (i == 6)
|
||||
target = (max > 30.0) ? max : 10.0;
|
||||
if (i == offset and proc_vec.at(i).cpu_p > 30.0)
|
||||
offset++;
|
||||
else if (proc_vec.at(i).cpu_p > target) {
|
||||
rotate(proc_vec.begin() + offset, proc_vec.begin() + i, proc_vec.begin() + i + 1);
|
||||
if (++x > 10) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tree_sort(vector<tree_proc>& proc_vec, const string& sorting, bool reverse, bool paused, int& c_index, const int index_max, bool collapsed) {
|
||||
if (proc_vec.size() > 1 and not paused) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 3: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().threads < b.entry.get().threads; }); break;
|
||||
case 5: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().mem < b.entry.get().mem; }); break;
|
||||
case 6: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_p < b.entry.get().cpu_p; }); break;
|
||||
case 7: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_c < b.entry.get().cpu_c; }); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 3: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().threads > b.entry.get().threads; }); break;
|
||||
case 5: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().mem > b.entry.get().mem; }); break;
|
||||
case 6: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_p > b.entry.get().cpu_p; }); break;
|
||||
case 7: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_c > b.entry.get().cpu_c; }); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& r : proc_vec) {
|
||||
r.entry.get().tree_index = (collapsed or r.entry.get().filtered ? index_max : c_index++);
|
||||
if (not r.children.empty()) {
|
||||
tree_sort(r.children, sorting, reverse, paused, c_index, (collapsed or r.entry.get().collapsed or r.entry.get().tree_index == (size_t)index_max));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto matches_filter(const proc_info& proc, const std::string& filter) -> bool {
|
||||
if (filter.starts_with("!")) {
|
||||
if (filter.size() == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// An incomplete regex throws, see issue https://github.com/aristocratos/btop/issues/1133
|
||||
try {
|
||||
std::regex regex { filter.substr(1), std::regex::extended };
|
||||
return std::regex_search(std::to_string(proc.pid), regex) || std::regex_search(proc.name, regex) ||
|
||||
std::regex_match(proc.cmd, regex) || std::regex_search(proc.user, regex);
|
||||
} catch (std::regex_error& /* unused */) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return std::to_string(proc.pid).contains(filter) || s_contains_ic(proc.name, filter) ||
|
||||
s_contains_ic(proc.cmd, filter) || s_contains_ic(proc.user, filter);
|
||||
}
|
||||
|
||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<tree_proc>& out_procs,
|
||||
int cur_depth, bool collapsed, const string& filter, bool found, bool no_update, bool should_filter) {
|
||||
bool filtering = false;
|
||||
|
||||
//? If filtering, include children of matching processes
|
||||
if (not found and (should_filter or not filter.empty())) {
|
||||
if (!matches_filter(cur_proc, filter)) {
|
||||
filtering = true;
|
||||
cur_proc.filtered = true;
|
||||
filter_found++;
|
||||
}
|
||||
else {
|
||||
found = true;
|
||||
cur_depth = 0;
|
||||
}
|
||||
}
|
||||
else if (cur_proc.filtered) cur_proc.filtered = false;
|
||||
|
||||
cur_proc.depth = cur_depth;
|
||||
|
||||
//? Set tree index position for process if not filtered out or currently in a collapsed sub-tree
|
||||
out_procs.push_back({ cur_proc, {} });
|
||||
if (not collapsed and not filtering) {
|
||||
cur_proc.tree_index = out_procs.size() - 1;
|
||||
|
||||
//? Try to find name of the binary file and append to program name if not the same
|
||||
if (cur_proc.short_cmd.empty() and not cur_proc.cmd.empty()) {
|
||||
std::string_view cmd_view = cur_proc.cmd;
|
||||
cmd_view = cmd_view.substr((size_t)0, std::min(cmd_view.find(' '), cmd_view.size()));
|
||||
cmd_view = cmd_view.substr(std::min(cmd_view.find_last_of('/') + 1, cmd_view.size()));
|
||||
cur_proc.short_cmd = string{cmd_view};
|
||||
}
|
||||
}
|
||||
else {
|
||||
cur_proc.tree_index = in_procs.size();
|
||||
}
|
||||
|
||||
//? Recursive iteration over all children
|
||||
for (auto& p : rng::equal_range(in_procs, cur_proc.pid, rng::less{}, &proc_info::ppid)) {
|
||||
if (collapsed and not filtering) {
|
||||
cur_proc.filtered = true;
|
||||
}
|
||||
|
||||
_tree_gen(p, in_procs, out_procs.back().children, cur_depth + 1, (collapsed or cur_proc.collapsed), filter, found, no_update, should_filter);
|
||||
|
||||
if (not no_update and not filtering and (collapsed or cur_proc.collapsed)) {
|
||||
//auto& parent = cur_proc;
|
||||
if (p.state != 'X') {
|
||||
cur_proc.cpu_p += p.cpu_p;
|
||||
cur_proc.cpu_c += p.cpu_c;
|
||||
cur_proc.mem += p.mem;
|
||||
cur_proc.threads += p.threads;
|
||||
}
|
||||
filter_found++;
|
||||
p.filtered = true;
|
||||
}
|
||||
else if (Config::getB("proc_aggregate") and p.state != 'X') {
|
||||
cur_proc.cpu_p += p.cpu_p;
|
||||
cur_proc.cpu_c += p.cpu_c;
|
||||
cur_proc.mem += p.mem;
|
||||
cur_proc.threads += p.threads;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _collect_prefixes(tree_proc &t, const bool is_last, const string &header) {
|
||||
const bool is_filtered = t.entry.get().filtered;
|
||||
if (is_filtered) t.entry.get().depth = 0;
|
||||
|
||||
if (!t.children.empty()) t.entry.get().prefix = header + (t.entry.get().collapsed ? "[+]─": "[-]─");
|
||||
else t.entry.get().prefix = header + (is_last ? " └─": " ├─");
|
||||
|
||||
for (auto child = t.children.begin(); child != t.children.end(); ++child) {
|
||||
_collect_prefixes(*child, child == (t.children.end() - 1),
|
||||
is_filtered ? "": header + (is_last ? " ": " │ "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto detect_container() -> std::optional<std::string> {
|
||||
std::error_code err;
|
||||
|
||||
if (fs::exists(fs::path("/run/.containerenv"), err)) {
|
||||
return std::make_optional(std::string { "podman" });
|
||||
}
|
||||
if (fs::exists(fs::path("/.dockerenv"), err)) {
|
||||
return std::make_optional(std::string { "docker" });
|
||||
}
|
||||
auto systemd_container = fs::path("/run/systemd/container");
|
||||
if (fs::exists(systemd_container, err)) {
|
||||
auto stream = std::ifstream { systemd_container };
|
||||
auto buf = std::string {};
|
||||
stream >> buf;
|
||||
return std::make_optional(buf);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
461
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/btop_shared.hpp
vendored
Normal file
461
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/btop_shared.hpp
vendored
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// From `man 3 getifaddrs`: <net/if.h> must be included before <ifaddrs.h>
|
||||
// clang-format off
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
// clang-format on
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
# include <kvm.h>
|
||||
#endif
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::deque;
|
||||
using std::string;
|
||||
using std::tuple;
|
||||
using std::vector;
|
||||
|
||||
using namespace std::literals; // for operator""s
|
||||
|
||||
void term_resize(bool force=false);
|
||||
void banner_gen();
|
||||
|
||||
extern void clean_quit(int sig);
|
||||
|
||||
namespace Global {
|
||||
extern const vector<array<string, 2>> Banner_src;
|
||||
extern const string Version;
|
||||
extern atomic<bool> quitting;
|
||||
extern string exit_error_msg;
|
||||
extern atomic<bool> thread_exception;
|
||||
extern string banner;
|
||||
extern atomic<bool> resized;
|
||||
extern string overlay;
|
||||
extern string clock;
|
||||
extern uid_t real_uid, set_uid;
|
||||
extern atomic<bool> init_conf;
|
||||
}
|
||||
|
||||
namespace Runner {
|
||||
extern atomic<bool> active;
|
||||
extern atomic<bool> reading;
|
||||
extern atomic<bool> stopping;
|
||||
extern atomic<bool> redraw;
|
||||
extern atomic<bool> coreNum_reset;
|
||||
extern pthread_t runner_id;
|
||||
extern bool pause_output;
|
||||
extern string debug_bg;
|
||||
|
||||
void run(const string& box="", bool no_update = false, bool force_redraw = false);
|
||||
void stop();
|
||||
|
||||
}
|
||||
|
||||
namespace Tools {
|
||||
//* Platform specific function for system_uptime (seconds since last restart)
|
||||
double system_uptime();
|
||||
}
|
||||
|
||||
namespace Shared {
|
||||
//* Initialize platform specific needed variables and check for errors
|
||||
void init();
|
||||
|
||||
extern long coreCount, page_size, clk_tck;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
struct KvmDeleter {
|
||||
void operator()(kvm_t* handle) {
|
||||
kvm_close(handle);
|
||||
}
|
||||
};
|
||||
using KvmPtr = std::unique_ptr<kvm_t, KvmDeleter>;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
namespace Gpu {
|
||||
#ifdef GPU_SUPPORT
|
||||
extern vector<string> box;
|
||||
extern int width, total_height, min_width, min_height;
|
||||
extern vector<int> x_vec, y_vec;
|
||||
extern vector<bool> redraw;
|
||||
extern int shown;
|
||||
extern int count;
|
||||
extern vector<int> shown_panels;
|
||||
extern vector<string> gpu_names;
|
||||
extern vector<int> gpu_b_height_offsets;
|
||||
extern long long gpu_pwr_total_max;
|
||||
|
||||
extern std::unordered_map<string, deque<long long>> shared_gpu_percent; // averages, power/vram total
|
||||
|
||||
const array mem_names { "used"s, "free"s };
|
||||
|
||||
//* Container for process information // TODO
|
||||
/*struct proc_info {
|
||||
unsigned int pid;
|
||||
unsigned long long mem;
|
||||
};*/
|
||||
|
||||
//* Container for supported Gpu::*::collect() functions
|
||||
struct gpu_info_supported {
|
||||
bool gpu_utilization = true,
|
||||
mem_utilization = true,
|
||||
gpu_clock = true,
|
||||
mem_clock = true,
|
||||
pwr_usage = true,
|
||||
pwr_state = true,
|
||||
temp_info = true,
|
||||
mem_total = true,
|
||||
mem_used = true,
|
||||
pcie_txrx = true,
|
||||
encoder_utilization = true,
|
||||
decoder_utilization = true;
|
||||
};
|
||||
|
||||
//* Per-device container for GPU info
|
||||
struct gpu_info {
|
||||
std::unordered_map<string, deque<long long>> gpu_percent = {
|
||||
{"gpu-totals", {}},
|
||||
{"gpu-vram-totals", {}},
|
||||
{"gpu-pwr-totals", {}},
|
||||
};
|
||||
unsigned int gpu_clock_speed; // MHz
|
||||
|
||||
long long pwr_usage; // mW
|
||||
long long pwr_max_usage = 255000;
|
||||
long long pwr_state;
|
||||
|
||||
deque<long long> temp = {0};
|
||||
long long temp_max = 110;
|
||||
|
||||
long long mem_total = 0;
|
||||
long long mem_used = 0;
|
||||
deque<long long> mem_utilization_percent = {0}; // TODO: properly handle GPUs that can't report some stats
|
||||
long long mem_clock_speed = 0; // MHz
|
||||
|
||||
long long pcie_tx = 0; // KB/s
|
||||
long long pcie_rx = 0;
|
||||
|
||||
long long encoder_utilization = 0;
|
||||
long long decoder_utilization = 0;
|
||||
|
||||
gpu_info_supported supported_functions;
|
||||
|
||||
// vector<proc_info> graphics_processes = {}; // TODO
|
||||
// vector<proc_info> compute_processes = {};
|
||||
};
|
||||
|
||||
namespace Nvml {
|
||||
extern bool shutdown();
|
||||
}
|
||||
namespace Rsmi {
|
||||
extern bool shutdown();
|
||||
}
|
||||
|
||||
//* Collect gpu stats and temperatures
|
||||
auto collect(bool no_update = false) -> vector<gpu_info>&;
|
||||
|
||||
//* Draw contents of gpu box using <gpus> as source
|
||||
string draw(const gpu_info& gpu, unsigned long index, bool force_redraw, bool data_same);
|
||||
#else
|
||||
struct gpu_info {
|
||||
bool supported = false;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Cpu {
|
||||
extern string box;
|
||||
extern int x, y, width, height, min_width, min_height;
|
||||
extern bool shown, redraw, got_sensors, cpu_temp_only, has_battery, supports_watts;
|
||||
extern string cpuName, cpuHz;
|
||||
extern vector<string> available_fields;
|
||||
extern vector<string> available_sensors;
|
||||
extern tuple<int, float, long, string> current_bat;
|
||||
extern std::optional<std::string> container_engine;
|
||||
|
||||
struct cpu_info {
|
||||
std::unordered_map<string, deque<long long>> cpu_percent = {
|
||||
{"total", {}},
|
||||
{"user", {}},
|
||||
{"nice", {}},
|
||||
{"system", {}},
|
||||
{"idle", {}},
|
||||
{"iowait", {}},
|
||||
{"irq", {}},
|
||||
{"softirq", {}},
|
||||
{"steal", {}},
|
||||
{"guest", {}},
|
||||
{"guest_nice", {}}
|
||||
};
|
||||
vector<deque<long long>> core_percent;
|
||||
vector<deque<long long>> temp;
|
||||
long long temp_max = 0;
|
||||
array<double, 3> load_avg;
|
||||
float usage_watts = 0;
|
||||
std::optional<std::vector<std::int32_t>> active_cpus;
|
||||
};
|
||||
|
||||
//* Collect cpu stats and temperatures
|
||||
auto collect(bool no_update = false) -> cpu_info&;
|
||||
|
||||
//* Draw contents of cpu box using <cpu> as source
|
||||
string draw(const cpu_info& cpu, const vector<Gpu::gpu_info>& gpu, bool force_redraw = false, bool data_same = false);
|
||||
|
||||
//* Parse /proc/cpu info for mapping of core ids
|
||||
auto get_core_mapping() -> std::unordered_map<int, int>;
|
||||
extern std::unordered_map<int, int> core_mapping;
|
||||
|
||||
auto get_cpuHz() -> string;
|
||||
|
||||
//* Get battery info from /sys
|
||||
auto get_battery() -> tuple<int, float, long, string>;
|
||||
|
||||
string trim_name(string);
|
||||
}
|
||||
|
||||
namespace Mem {
|
||||
extern string box;
|
||||
extern int x, y, width, height, min_width, min_height;
|
||||
extern bool has_swap, shown, redraw;
|
||||
const array mem_names { "used"s, "available"s, "cached"s, "free"s };
|
||||
const array swap_names { "swap_used"s, "swap_free"s };
|
||||
extern int disk_ios;
|
||||
|
||||
struct disk_info {
|
||||
std::filesystem::path dev;
|
||||
string name;
|
||||
string fstype{}; // defaults to ""
|
||||
std::filesystem::path stat{}; // defaults to ""
|
||||
int64_t total{};
|
||||
int64_t used{};
|
||||
int64_t free{};
|
||||
int used_percent{};
|
||||
int free_percent{};
|
||||
|
||||
array<int64_t, 3> old_io = {0, 0, 0};
|
||||
deque<long long> io_read = {};
|
||||
deque<long long> io_write = {};
|
||||
deque<long long> io_activity = {};
|
||||
};
|
||||
|
||||
struct mem_info {
|
||||
std::unordered_map<string, uint64_t> stats =
|
||||
{{"used", 0}, {"available", 0}, {"cached", 0}, {"free", 0},
|
||||
{"swap_total", 0}, {"swap_used", 0}, {"swap_free", 0}};
|
||||
std::unordered_map<string, deque<long long>> percent =
|
||||
{{"used", {}}, {"available", {}}, {"cached", {}}, {"free", {}},
|
||||
{"swap_total", {}}, {"swap_used", {}}, {"swap_free", {}}};
|
||||
std::unordered_map<string, disk_info> disks;
|
||||
vector<string> disks_order;
|
||||
};
|
||||
|
||||
//?* Get total system memory
|
||||
uint64_t get_totalMem();
|
||||
|
||||
//* Collect mem & disks stats
|
||||
auto collect(bool no_update = false) -> mem_info&;
|
||||
|
||||
//* Draw contents of mem box using <mem> as source
|
||||
string draw(const mem_info& mem, bool force_redraw = false, bool data_same = false);
|
||||
|
||||
}
|
||||
|
||||
namespace Net {
|
||||
extern string box;
|
||||
extern int x, y, width, height, min_width, min_height;
|
||||
extern bool shown, redraw;
|
||||
extern string selected_iface;
|
||||
extern vector<string> interfaces;
|
||||
extern bool rescale;
|
||||
extern std::unordered_map<string, uint64_t> graph_max;
|
||||
|
||||
struct net_stat {
|
||||
uint64_t speed{};
|
||||
uint64_t top{};
|
||||
uint64_t total{};
|
||||
uint64_t last{};
|
||||
uint64_t offset{};
|
||||
uint64_t rollover{};
|
||||
};
|
||||
|
||||
struct net_info {
|
||||
std::unordered_map<string, deque<long long>> bandwidth = { {"download", {}}, {"upload", {}} };
|
||||
std::unordered_map<string, net_stat> stat = { {"download", {}}, {"upload", {}} };
|
||||
string ipv4{}; // defaults to ""
|
||||
string ipv6{}; // defaults to ""
|
||||
bool connected{};
|
||||
};
|
||||
|
||||
class IfAddrsPtr {
|
||||
struct ifaddrs* ifaddr;
|
||||
int status;
|
||||
public:
|
||||
IfAddrsPtr() { status = getifaddrs(&ifaddr); }
|
||||
~IfAddrsPtr() noexcept { freeifaddrs(ifaddr); }
|
||||
IfAddrsPtr(const IfAddrsPtr &) = delete;
|
||||
IfAddrsPtr& operator=(IfAddrsPtr& other) = delete;
|
||||
IfAddrsPtr(IfAddrsPtr &&) = delete;
|
||||
IfAddrsPtr& operator=(IfAddrsPtr&& other) = delete;
|
||||
[[nodiscard]] constexpr auto operator()() -> struct ifaddrs* { return ifaddr; }
|
||||
[[nodiscard]] constexpr auto get() -> struct ifaddrs* { return ifaddr; }
|
||||
[[nodiscard]] constexpr auto get_status() const noexcept -> int { return status; };
|
||||
};
|
||||
|
||||
extern std::unordered_map<string, net_info> current_net;
|
||||
|
||||
//* Collect net upload/download stats
|
||||
auto collect(bool no_update=false) -> net_info&;
|
||||
|
||||
//* Draw contents of net box using <net> as source
|
||||
string draw(const net_info& net, bool force_redraw = false, bool data_same = false);
|
||||
}
|
||||
|
||||
namespace Proc {
|
||||
extern atomic<int> numpids;
|
||||
|
||||
extern string box;
|
||||
extern int x, y, width, height, min_width, min_height;
|
||||
extern bool shown, redraw;
|
||||
extern int select_max;
|
||||
extern atomic<int> detailed_pid;
|
||||
extern int selected_pid, start, selected, collapse, expand, filter_found, selected_depth, toggle_children;
|
||||
extern string selected_name;
|
||||
|
||||
//? Contains the valid sorting options for processes
|
||||
const vector<string> sort_vector = {
|
||||
"pid",
|
||||
"name",
|
||||
"command",
|
||||
"threads",
|
||||
"user",
|
||||
"memory",
|
||||
"cpu direct",
|
||||
"cpu lazy",
|
||||
};
|
||||
|
||||
//? Translation from process state char to explanative string
|
||||
const std::unordered_map<char, string> proc_states = {
|
||||
{'R', "Running"},
|
||||
{'S', "Sleeping"},
|
||||
{'D', "Waiting"},
|
||||
{'Z', "Zombie"},
|
||||
{'T', "Stopped"},
|
||||
{'t', "Tracing"},
|
||||
{'X', "Dead"},
|
||||
{'x', "Dead"},
|
||||
{'K', "Wakekill"},
|
||||
{'W', "Unknown"},
|
||||
{'P', "Parked"}
|
||||
};
|
||||
|
||||
//* Container for process information
|
||||
struct proc_info {
|
||||
size_t pid{};
|
||||
string name{}; // defaults to ""
|
||||
string cmd{}; // defaults to ""
|
||||
string short_cmd{}; // defaults to ""
|
||||
size_t threads{};
|
||||
int name_offset{};
|
||||
string user{}; // defaults to ""
|
||||
uint64_t mem{};
|
||||
double cpu_p{}; // defaults to = 0.0
|
||||
double cpu_c{}; // defaults to = 0.0
|
||||
char state = '0';
|
||||
int64_t p_nice{};
|
||||
uint64_t ppid{};
|
||||
uint64_t cpu_s{};
|
||||
uint64_t cpu_t{};
|
||||
uint64_t death_time{};
|
||||
string prefix{}; // defaults to ""
|
||||
size_t depth{};
|
||||
size_t tree_index{};
|
||||
bool collapsed{};
|
||||
bool filtered{};
|
||||
};
|
||||
|
||||
//* Container for process info box
|
||||
struct detail_container {
|
||||
size_t last_pid{};
|
||||
bool skip_smaps{};
|
||||
proc_info entry;
|
||||
string elapsed, parent, status, io_read, io_write, memory;
|
||||
long long first_mem = -1;
|
||||
deque<long long> cpu_percent;
|
||||
deque<long long> mem_bytes;
|
||||
};
|
||||
|
||||
//? Contains all info for proc detailed box
|
||||
extern detail_container detailed;
|
||||
|
||||
//* Collect and sort process information from /proc
|
||||
auto collect(bool no_update = false) -> vector<proc_info>&;
|
||||
|
||||
//* Update current selection and view, returns -1 if no change otherwise the current selection
|
||||
int selection(const std::string_view cmd_key);
|
||||
|
||||
//* Draw contents of proc box using <plist> as data source
|
||||
string draw(const vector<proc_info>& plist, bool force_redraw = false, bool data_same = false);
|
||||
|
||||
struct tree_proc {
|
||||
std::reference_wrapper<proc_info> entry;
|
||||
vector<tree_proc> children;
|
||||
};
|
||||
|
||||
//* Change priority (nice) of pid, returns true on success otherwise false
|
||||
bool set_priority(pid_t pid, int priority);
|
||||
|
||||
//* Sort vector of proc_info's
|
||||
void proc_sorter(vector<proc_info>& proc_vec, const string& sorting, bool reverse, bool tree = false);
|
||||
|
||||
//* Recursive sort of process tree
|
||||
void tree_sort(vector<tree_proc>& proc_vec, const string& sorting, bool reverse, bool paused,
|
||||
int& c_index, const int index_max, bool collapsed = false);
|
||||
|
||||
auto matches_filter(const proc_info& proc, const std::string& filter) -> bool;
|
||||
|
||||
//* Generate process tree list
|
||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<tree_proc>& out_procs,
|
||||
int cur_depth, bool collapsed, const string& filter,
|
||||
bool found = false, bool no_update = false, bool should_filter = false);
|
||||
|
||||
//* Build prefixes for tree view
|
||||
void _collect_prefixes(tree_proc& t, bool is_last, const string &header = "");
|
||||
}
|
||||
|
||||
/// Detect container engine.
|
||||
auto detect_container() -> std::optional<std::string>;
|
||||
|
|
@ -0,0 +1,454 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "btop_tools.hpp"
|
||||
#include "btop_config.hpp"
|
||||
#include "btop_theme.hpp"
|
||||
|
||||
using std::round;
|
||||
using std::stoi;
|
||||
using std::to_string;
|
||||
using std::vector;
|
||||
using std::views::iota;
|
||||
|
||||
using namespace Tools;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
string Term::fg, Term::bg;
|
||||
string Fx::reset = reset_base;
|
||||
|
||||
namespace Theme {
|
||||
|
||||
fs::path theme_dir;
|
||||
fs::path user_theme_dir;
|
||||
fs::path custom_theme_dir;
|
||||
vector<string> themes;
|
||||
std::unordered_map<string, string> colors;
|
||||
std::unordered_map<string, array<int, 3>> rgbs;
|
||||
std::unordered_map<string, array<string, 101>> gradients;
|
||||
|
||||
const std::unordered_map<string, string> Default_theme = {
|
||||
{ "main_bg", "#00" },
|
||||
{ "main_fg", "#cc" },
|
||||
{ "title", "#ee" },
|
||||
{ "hi_fg", "#b54040" },
|
||||
{ "selected_bg", "#6a2f2f" },
|
||||
{ "selected_fg", "#ee" },
|
||||
{ "inactive_fg", "#40" },
|
||||
{ "graph_text", "#60" },
|
||||
{ "meter_bg", "#40" },
|
||||
{ "proc_misc", "#0de756" },
|
||||
{ "cpu_box", "#556d59" },
|
||||
{ "mem_box", "#6c6c4b" },
|
||||
{ "net_box", "#5c588d" },
|
||||
{ "proc_box", "#805252" },
|
||||
{ "div_line", "#30" },
|
||||
{ "temp_start", "#4897d4" },
|
||||
{ "temp_mid", "#5474e8" },
|
||||
{ "temp_end", "#ff40b6" },
|
||||
{ "cpu_start", "#77ca9b" },
|
||||
{ "cpu_mid", "#cbc06c" },
|
||||
{ "cpu_end", "#dc4c4c" },
|
||||
{ "free_start", "#384f21" },
|
||||
{ "free_mid", "#b5e685" },
|
||||
{ "free_end", "#dcff85" },
|
||||
{ "cached_start", "#163350" },
|
||||
{ "cached_mid", "#74e6fc" },
|
||||
{ "cached_end", "#26c5ff" },
|
||||
{ "available_start", "#4e3f0e" },
|
||||
{ "available_mid", "#ffd77a" },
|
||||
{ "available_end", "#ffb814" },
|
||||
{ "used_start", "#592b26" },
|
||||
{ "used_mid", "#d9626d" },
|
||||
{ "used_end", "#ff4769" },
|
||||
{ "download_start", "#291f75" },
|
||||
{ "download_mid", "#4f43a3" },
|
||||
{ "download_end", "#b0a9de" },
|
||||
{ "upload_start", "#620665" },
|
||||
{ "upload_mid", "#7d4180" },
|
||||
{ "upload_end", "#dcafde" },
|
||||
{ "process_start", "#80d0a3" },
|
||||
{ "process_mid", "#dcd179" },
|
||||
{ "process_end", "#d45454" },
|
||||
{ "proc_pause_bg", "#b54040" }
|
||||
};
|
||||
|
||||
const std::unordered_map<string, string> TTY_theme = {
|
||||
{ "main_bg", "\x1b[0;40m" },
|
||||
{ "main_fg", "\x1b[37m" },
|
||||
{ "title", "\x1b[97m" },
|
||||
{ "hi_fg", "\x1b[91m" },
|
||||
{ "selected_bg", "\x1b[41m" },
|
||||
{ "selected_fg", "\x1b[97m" },
|
||||
{ "inactive_fg", "\x1b[90m" },
|
||||
{ "graph_text", "\x1b[90m" },
|
||||
{ "meter_bg", "\x1b[90m" },
|
||||
{ "proc_misc", "\x1b[92m" },
|
||||
{ "cpu_box", "\x1b[32m" },
|
||||
{ "mem_box", "\x1b[33m" },
|
||||
{ "net_box", "\x1b[35m" },
|
||||
{ "proc_box", "\x1b[31m" },
|
||||
{ "div_line", "\x1b[90m" },
|
||||
{ "temp_start", "\x1b[94m" },
|
||||
{ "temp_mid", "\x1b[96m" },
|
||||
{ "temp_end", "\x1b[95m" },
|
||||
{ "cpu_start", "\x1b[92m" },
|
||||
{ "cpu_mid", "\x1b[93m" },
|
||||
{ "cpu_end", "\x1b[91m" },
|
||||
{ "free_start", "\x1b[32m" },
|
||||
{ "free_mid", "" },
|
||||
{ "free_end", "\x1b[92m" },
|
||||
{ "cached_start", "\x1b[36m" },
|
||||
{ "cached_mid", "" },
|
||||
{ "cached_end", "\x1b[96m" },
|
||||
{ "available_start", "\x1b[33m" },
|
||||
{ "available_mid", "" },
|
||||
{ "available_end", "\x1b[93m" },
|
||||
{ "used_start", "\x1b[31m" },
|
||||
{ "used_mid", "" },
|
||||
{ "used_end", "\x1b[91m" },
|
||||
{ "download_start", "\x1b[34m" },
|
||||
{ "download_mid", "" },
|
||||
{ "download_end", "\x1b[94m" },
|
||||
{ "upload_start", "\x1b[35m" },
|
||||
{ "upload_mid", "" },
|
||||
{ "upload_end", "\x1b[95m" },
|
||||
{ "process_start", "\x1b[32m" },
|
||||
{ "process_mid", "\x1b[33m" },
|
||||
{ "process_end", "\x1b[31m" },
|
||||
{ "proc_pause_bg", "\x1b[41m" },
|
||||
};
|
||||
|
||||
namespace {
|
||||
//* Convert 24-bit colors to 256 colors
|
||||
int truecolor_to_256(const int& r, const int& g, const int& b) {
|
||||
//? Use upper 232-255 greyscale values if the downscaled red, green and blue are the same value
|
||||
if (const int red = round((double)r / 11); red == round((double)g / 11) and red == round((double)b / 11)) {
|
||||
return 232 + red;
|
||||
}
|
||||
//? Else use 6x6x6 color cube to calculate approximate colors
|
||||
else {
|
||||
return round((double)r / 51) * 36 + round((double)g / 51) * 6 + round((double)b / 51) + 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string hex_to_color(string hexa, bool t_to_256, const string& depth) {
|
||||
if (hexa.size() > 1) {
|
||||
hexa.erase(0, 1);
|
||||
for (auto& c : hexa) {
|
||||
if (not isxdigit(c)) {
|
||||
Logger::error("Invalid hex value: " + hexa);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
string pre = Fx::e + (depth == "fg" ? "38" : "48") + ";" + (t_to_256 ? "5;" : "2;");
|
||||
|
||||
if (hexa.size() == 2) {
|
||||
int h_int = stoi(hexa, nullptr, 16);
|
||||
if (t_to_256) {
|
||||
return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m";
|
||||
} else {
|
||||
string h_str = to_string(h_int);
|
||||
return pre + h_str + ";" + h_str + ";" + h_str + "m";
|
||||
}
|
||||
}
|
||||
else if (hexa.size() == 6) {
|
||||
if (t_to_256) {
|
||||
return pre + to_string(truecolor_to_256(
|
||||
stoi(hexa.substr(0, 2), nullptr, 16),
|
||||
stoi(hexa.substr(2, 2), nullptr, 16),
|
||||
stoi(hexa.substr(4, 2), nullptr, 16))) + "m";
|
||||
} else {
|
||||
return pre +
|
||||
to_string(stoi(hexa.substr(0, 2), nullptr, 16)) + ";" +
|
||||
to_string(stoi(hexa.substr(2, 2), nullptr, 16)) + ";" +
|
||||
to_string(stoi(hexa.substr(4, 2), nullptr, 16)) + "m";
|
||||
}
|
||||
}
|
||||
else Logger::error("Invalid size of hex value: " + hexa);
|
||||
}
|
||||
else Logger::error("Hex value missing: " + hexa);
|
||||
return "";
|
||||
}
|
||||
|
||||
string dec_to_color(int r, int g, int b, bool t_to_256, const string& depth) {
|
||||
string pre = Fx::e + (depth == "fg" ? "38" : "48") + ";" + (t_to_256 ? "5;" : "2;");
|
||||
r = std::clamp(r, 0, 255);
|
||||
g = std::clamp(g, 0, 255);
|
||||
b = std::clamp(b, 0, 255);
|
||||
if (t_to_256) return pre + to_string(truecolor_to_256(r, g, b)) + "m";
|
||||
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
||||
}
|
||||
|
||||
namespace {
|
||||
//* Convert hex color to a array of decimals
|
||||
array<int, 3> hex_to_dec(string hexa) {
|
||||
if (hexa.size() > 1) {
|
||||
hexa.erase(0, 1);
|
||||
for (auto& c : hexa) {
|
||||
if (not isxdigit(c))
|
||||
return array{-1, -1, -1};
|
||||
}
|
||||
|
||||
if (hexa.size() == 2) {
|
||||
int h_int = stoi(hexa, nullptr, 16);
|
||||
return array{h_int, h_int, h_int};
|
||||
}
|
||||
else if (hexa.size() == 6) {
|
||||
return array{
|
||||
stoi(hexa.substr(0, 2), nullptr, 16),
|
||||
stoi(hexa.substr(2, 2), nullptr, 16),
|
||||
stoi(hexa.substr(4, 2), nullptr, 16)
|
||||
};
|
||||
}
|
||||
}
|
||||
return {-1 ,-1 ,-1};
|
||||
}
|
||||
|
||||
//* Generate colors and rgb decimal vectors for the theme
|
||||
void generateColors(const std::unordered_map<string, string>& source) {
|
||||
vector<string> t_rgb;
|
||||
string depth;
|
||||
bool t_to_256 = Config::getB("lowcolor");
|
||||
colors.clear(); rgbs.clear();
|
||||
for (const auto& [name, color] : Default_theme) {
|
||||
if (name == "main_bg" and not Config::getB("theme_background")) {
|
||||
colors[name] = "\x1b[49m";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
depth = (name.ends_with("bg") and name != "meter_bg") ? "bg" : "fg";
|
||||
if (source.contains(name)) {
|
||||
if (name == "main_bg" and source.at(name).empty()) {
|
||||
colors[name] = "\x1b[49m";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
else if (source.at(name).empty() and (name.ends_with("_mid") or name.ends_with("_end"))) {
|
||||
colors[name] = "";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
else if (source.at(name).starts_with('#')) {
|
||||
colors[name] = hex_to_color(source.at(name), t_to_256, depth);
|
||||
rgbs[name] = hex_to_dec(source.at(name));
|
||||
}
|
||||
else if (not source.at(name).empty()) {
|
||||
t_rgb = ssplit(source.at(name));
|
||||
if (t_rgb.size() != 3) {
|
||||
Logger::error("Invalid RGB decimal value: \"" + source.at(name) + "\"");
|
||||
} else {
|
||||
colors[name] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), t_to_256, depth);
|
||||
rgbs[name] = array{stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2])};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (not colors.contains(name) and not is_in(name, "meter_bg", "process_start", "process_mid", "process_end", "graph_text")) {
|
||||
Logger::debug("Missing color value for \"" + name + "\". Using value from default.");
|
||||
colors[name] = hex_to_color(color, t_to_256, depth);
|
||||
rgbs[name] = hex_to_dec(color);
|
||||
}
|
||||
}
|
||||
//? Set fallback values for optional colors not defined in theme file
|
||||
if (not colors.contains("meter_bg")) {
|
||||
colors["meter_bg"] = colors.at("inactive_fg");
|
||||
rgbs["meter_bg"] = rgbs.at("inactive_fg");
|
||||
}
|
||||
if (not colors.contains("process_start")) {
|
||||
colors["process_start"] = colors.at("cpu_start");
|
||||
colors["process_mid"] = colors.at("cpu_mid");
|
||||
colors["process_end"] = colors.at("cpu_end");
|
||||
rgbs["process_start"] = rgbs.at("cpu_start");
|
||||
rgbs["process_mid"] = rgbs.at("cpu_mid");
|
||||
rgbs["process_end"] = rgbs.at("cpu_end");
|
||||
}
|
||||
if (not colors.contains("graph_text")) {
|
||||
colors["graph_text"] = colors.at("inactive_fg");
|
||||
rgbs["graph_text"] = rgbs.at("inactive_fg");
|
||||
}
|
||||
}
|
||||
|
||||
//* Generate color gradients from two or three colors, 101 values indexed 0-100
|
||||
void generateGradients() {
|
||||
gradients.clear();
|
||||
bool t_to_256 = Config::getB("lowcolor");
|
||||
|
||||
//? Insert values for processes greyscale gradient and processes color gradient
|
||||
rgbs.insert({
|
||||
{ "proc_start", rgbs["main_fg"] },
|
||||
{ "proc_mid", {-1, -1, -1} },
|
||||
{ "proc_end", rgbs["inactive_fg"] },
|
||||
{ "proc_color_start", rgbs["inactive_fg"] },
|
||||
{ "proc_color_mid", {-1, -1, -1} },
|
||||
{ "proc_color_end", rgbs["process_start"] },
|
||||
});
|
||||
|
||||
for (const auto& [name, source_arr] : rgbs) {
|
||||
if (not name.ends_with("_start")) continue;
|
||||
const string color_name { rtrim(name, "_start") };
|
||||
|
||||
//? input_colors[start,mid,end][red,green,blue]
|
||||
const array<array<int, 3>, 3> input_colors = {
|
||||
source_arr,
|
||||
rgbs[color_name + "_mid"],
|
||||
rgbs[color_name + "_end"]
|
||||
};
|
||||
|
||||
//? output_colors[red,green,blue][0-100]
|
||||
array<array<int, 3>, 101> output_colors;
|
||||
output_colors[0][0] = -1;
|
||||
|
||||
//? Only start iteration if gradient has an end color defined
|
||||
if (input_colors[2][0] >= 0) {
|
||||
|
||||
//? Split iteration in two passes of 50 + 51 instead of one pass of 101 if gradient has start, mid and end values defined
|
||||
int current_range = (input_colors[1][0] >= 0) ? 50 : 100;
|
||||
for (int rgb : iota(0, 3)) {
|
||||
int start = 0, offset = 0;
|
||||
int end = (current_range == 50) ? 1 : 2;
|
||||
for (int i : iota(0, 101)) {
|
||||
output_colors[i][rgb] = input_colors[start][rgb] + (i - offset) * (input_colors[end][rgb] - input_colors[start][rgb]) / current_range;
|
||||
|
||||
//? Switch source arrays from start->mid to mid->end at 50 passes if mid is defined
|
||||
if (i == current_range) { ++start; ++end; offset = 50; }
|
||||
}
|
||||
}
|
||||
}
|
||||
//? Generate color escape codes for the generated rgb decimals
|
||||
array<string, 101> color_gradient;
|
||||
if (output_colors[0][0] != -1) {
|
||||
for (int y = 0; const auto& [red, green, blue] : output_colors)
|
||||
color_gradient[y++] = dec_to_color(red, green, blue, t_to_256);
|
||||
}
|
||||
else {
|
||||
//? If only start was defined fill array with start color
|
||||
color_gradient.fill(colors[name]);
|
||||
}
|
||||
gradients[color_name] = std::move(color_gradient);
|
||||
}
|
||||
}
|
||||
|
||||
//* Set colors and generate gradients for the TTY theme
|
||||
void generateTTYColors() {
|
||||
rgbs.clear();
|
||||
gradients.clear();
|
||||
colors = TTY_theme;
|
||||
if (not Config::getB("theme_background"))
|
||||
colors["main_bg"] = "\x1b[49m";
|
||||
|
||||
for (const auto& c : colors) {
|
||||
if (not c.first.ends_with("_start")) continue;
|
||||
const string base_name { rtrim(c.first, "_start") };
|
||||
string section = "_start";
|
||||
int split = colors.at(base_name + "_mid").empty() ? 50 : 33;
|
||||
for (int i : iota(0, 101)) {
|
||||
gradients[base_name][i] = colors.at(base_name + section);
|
||||
if (i == split) {
|
||||
section = (split == 33) ? "_mid" : "_end";
|
||||
split *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Load a .theme file from disk
|
||||
auto loadFile(const string& filename) {
|
||||
const fs::path filepath = filename;
|
||||
if (not fs::exists(filepath))
|
||||
return Default_theme;
|
||||
|
||||
std::ifstream themefile(filepath);
|
||||
if (themefile.good()) {
|
||||
std::unordered_map<string, string> theme_out;
|
||||
Logger::debug("Loading theme file: " + filename);
|
||||
while (not themefile.bad()) {
|
||||
if (themefile.peek() == '#') {
|
||||
themefile.ignore(SSmax, '\n');
|
||||
continue;
|
||||
}
|
||||
themefile.ignore(SSmax, '[');
|
||||
if (themefile.eof()) break;
|
||||
string name, value;
|
||||
getline(themefile, name, ']');
|
||||
if (not Default_theme.contains(name)) {
|
||||
themefile.ignore(SSmax, '\n');
|
||||
continue;
|
||||
}
|
||||
themefile.ignore(SSmax, '=');
|
||||
themefile >> std::ws;
|
||||
if (themefile.eof()) break;
|
||||
if (themefile.peek() == '"') {
|
||||
themefile.ignore(1);
|
||||
getline(themefile, value, '"');
|
||||
themefile.ignore(SSmax, '\n');
|
||||
}
|
||||
else getline(themefile, value, '\n');
|
||||
|
||||
theme_out[name] = value;
|
||||
}
|
||||
return theme_out;
|
||||
}
|
||||
return Default_theme;
|
||||
}
|
||||
}
|
||||
|
||||
void updateThemes() {
|
||||
themes.clear();
|
||||
themes.push_back("Default");
|
||||
themes.push_back("TTY");
|
||||
|
||||
//? Priority: custom_theme_dir -> user_theme_dir -> theme_dir
|
||||
for (const auto& path : { custom_theme_dir, user_theme_dir, theme_dir } ) {
|
||||
if (path.empty()) continue;
|
||||
for (auto& file : fs::directory_iterator(path)) {
|
||||
if (file.path().extension() == ".theme" and access(file.path().c_str(), R_OK) != -1 and not v_contains(themes, file.path().c_str())) {
|
||||
themes.push_back(file.path().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setTheme() {
|
||||
const auto& theme = Config::getS("color_theme");
|
||||
fs::path theme_path;
|
||||
for (const fs::path p : themes) {
|
||||
if (p == theme or p.stem() == theme or p.filename() == theme) {
|
||||
theme_path = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (theme == "TTY" or Config::getB("tty_mode"))
|
||||
generateTTYColors();
|
||||
else {
|
||||
generateColors((theme == "Default" or theme_path.empty() ? Default_theme : loadFile(theme_path)));
|
||||
generateGradients();
|
||||
}
|
||||
Term::fg = colors.at("main_fg");
|
||||
Term::bg = colors.at("main_bg");
|
||||
Fx::reset = Fx::reset_base + Term::fg + Term::bg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
using std::array;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace Theme {
|
||||
extern std::filesystem::path theme_dir;
|
||||
extern std::filesystem::path user_theme_dir;
|
||||
extern std::filesystem::path custom_theme_dir;
|
||||
|
||||
//* Contains "Default" and "TTY" at indices 0 and 1, otherwise full paths to theme files
|
||||
extern vector<string> themes;
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
//* Args hexa: ["#000000"-"#ffffff"] for color, ["#00"-"#ff"] for greyscale
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string hex_to_color(string hexa, bool t_to_256=false, const string& depth="fg");
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
//* Args r: [0-255], g: [0-255], b: [0-255]
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string dec_to_color(int r, int g, int b, bool t_to_256=false, const string& depth="fg");
|
||||
|
||||
//* Update list of paths for available themes
|
||||
void updateThemes();
|
||||
|
||||
//* Set current theme from current "color_theme" value in config
|
||||
void setTheme();
|
||||
|
||||
extern std::unordered_map<string, string> colors;
|
||||
extern std::unordered_map<string, array<int, 3>> rgbs;
|
||||
extern std::unordered_map<string, array<string, 101>> gradients;
|
||||
|
||||
//* Return escape code for color <name>
|
||||
inline const string& c(const string& name) { return colors.at(name); }
|
||||
|
||||
//* Return array of escape codes for color gradient <name>
|
||||
inline const array<string, 101>& g(const string& name) { return gradients.at(name); }
|
||||
|
||||
//* Return array of red, green and blue in decimal for color <name>
|
||||
inline const std::array<int, 3>& dec(const string& name) { return rgbs.at(name); }
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,714 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <codecvt>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "widechar_width.hpp"
|
||||
#include "btop_shared.hpp"
|
||||
#include "btop_tools.hpp"
|
||||
#include "btop_config.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::floor;
|
||||
using std::flush;
|
||||
using std::max;
|
||||
using std::string_view;
|
||||
using std::to_string;
|
||||
|
||||
using namespace std::literals; // to use operator""s
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace rng = std::ranges;
|
||||
|
||||
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
||||
|
||||
//* Collection of escape codes and functions for terminal manipulation
|
||||
namespace Term {
|
||||
|
||||
atomic<bool> initialized{};
|
||||
atomic<int> width{};
|
||||
atomic<int> height{};
|
||||
string current_tty;
|
||||
|
||||
namespace {
|
||||
struct termios initial_settings;
|
||||
|
||||
//* Toggle terminal input echo
|
||||
bool echo(bool on=true) {
|
||||
struct termios settings;
|
||||
if (tcgetattr(STDIN_FILENO, &settings)) return false;
|
||||
if (on) settings.c_lflag |= ECHO;
|
||||
else settings.c_lflag &= ~(ECHO);
|
||||
return 0 == tcsetattr(STDIN_FILENO, TCSANOW, &settings);
|
||||
}
|
||||
|
||||
//* Toggle need for return key when reading input
|
||||
bool linebuffered(bool on=true) {
|
||||
struct termios settings;
|
||||
if (tcgetattr(STDIN_FILENO, &settings)) return false;
|
||||
if (on) settings.c_lflag |= ICANON;
|
||||
else {
|
||||
settings.c_lflag &= ~(ICANON);
|
||||
settings.c_cc[VMIN] = 0;
|
||||
settings.c_cc[VTIME] = 0;
|
||||
}
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &settings)) return false;
|
||||
if (on) setlinebuf(stdin);
|
||||
else setbuf(stdin, nullptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool refresh(bool only_check) {
|
||||
// Query dimensions of '/dev/tty' of the 'STDOUT_FILENO' isn't available.
|
||||
// This variable is set in those cases to avoid calls to ioctl
|
||||
constinit static bool uses_dev_tty = false;
|
||||
struct winsize wsize {};
|
||||
if (uses_dev_tty || ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsize) < 0 || (wsize.ws_col == 0 && wsize.ws_row == 0)) {
|
||||
Logger::error(R"(Couldn't determine terminal size of "STDOUT_FILENO"!)");
|
||||
auto dev_tty = open("/dev/tty", O_RDONLY | O_CLOEXEC);
|
||||
if (dev_tty != -1) {
|
||||
ioctl(dev_tty, TIOCGWINSZ, &wsize);
|
||||
close(dev_tty);
|
||||
}
|
||||
else {
|
||||
Logger::error(R"(Couldn't determine terminal size of "/dev/tty"!)");
|
||||
return false;
|
||||
}
|
||||
uses_dev_tty = true;
|
||||
}
|
||||
if (width != wsize.ws_col or height != wsize.ws_row) {
|
||||
if (not only_check) {
|
||||
width = wsize.ws_col;
|
||||
height = wsize.ws_row;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto get_min_size(const string& boxes) -> array<int, 2> {
|
||||
bool cpu = boxes.find("cpu") != string::npos;
|
||||
bool mem = boxes.find("mem") != string::npos;
|
||||
bool net = boxes.find("net") != string::npos;
|
||||
bool proc = boxes.find("proc") != string::npos;
|
||||
#ifdef GPU_SUPPORT
|
||||
int gpu = 0;
|
||||
if (Gpu::count > 0)
|
||||
for (char i = '0'; i <= '5'; i++)
|
||||
gpu += (boxes.contains("gpu"s + i) ? 1 : 0);
|
||||
#endif
|
||||
int width = 0;
|
||||
if (mem) width = Mem::min_width;
|
||||
else if (net) width = Mem::min_width;
|
||||
width += (proc ? Proc::min_width : 0);
|
||||
if (cpu and width < Cpu::min_width) width = Cpu::min_width;
|
||||
#ifdef GPU_SUPPORT
|
||||
if (gpu != 0 and width < Gpu::min_width) width = Gpu::min_width;
|
||||
#endif
|
||||
|
||||
int height = (cpu ? Cpu::min_height : 0);
|
||||
if (proc) height += Proc::min_height;
|
||||
else height += (mem ? Mem::min_height : 0) + (net ? Net::min_height : 0);
|
||||
#ifdef GPU_SUPPORT
|
||||
for (int i = 0; i < gpu; i++)
|
||||
height += Gpu::gpu_b_height_offsets[i] + 4;
|
||||
#endif
|
||||
|
||||
return { width, height };
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if (not initialized) {
|
||||
initialized = (bool)isatty(STDIN_FILENO);
|
||||
if (initialized) {
|
||||
tcgetattr(STDIN_FILENO, &initial_settings);
|
||||
current_tty = (ttyname(STDIN_FILENO) != nullptr ? static_cast<string>(ttyname(STDIN_FILENO)) : "unknown");
|
||||
|
||||
//? Disable stream sync - this does not seem to work on OpenBSD
|
||||
#ifndef __OpenBSD__
|
||||
cout.sync_with_stdio(false);
|
||||
#endif
|
||||
|
||||
//? Disable stream ties
|
||||
cout.tie(nullptr);
|
||||
echo(false);
|
||||
linebuffered(false);
|
||||
refresh();
|
||||
|
||||
cout << alt_screen << hide_cursor << mouse_on << flush;
|
||||
Global::resized = false;
|
||||
}
|
||||
}
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void restore() {
|
||||
if (initialized) {
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &initial_settings);
|
||||
cout << mouse_off << clear << Fx::reset << normal_screen << show_cursor << flush;
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
// ! Disabled due to issue when compiling with musl, reverted back to using regex
|
||||
// namespace Fx {
|
||||
// string uncolor(const string& s) {
|
||||
// string out = s;
|
||||
// for (size_t offset = 0, start_pos = 0, end_pos = 0;;) {
|
||||
// start_pos = (offset == 0) ? out.find('\x1b') : offset;
|
||||
// if (start_pos == string::npos)
|
||||
// break;
|
||||
// offset = start_pos + 1;
|
||||
// end_pos = out.find('m', offset);
|
||||
// if (end_pos == string::npos)
|
||||
// break;
|
||||
// else if (auto next_pos = out.find('\x1b', offset); not isdigit(out[end_pos - 1]) or end_pos > next_pos) {
|
||||
// offset = next_pos;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// out.erase(start_pos, (end_pos - start_pos)+1);
|
||||
// offset = 0;
|
||||
// }
|
||||
// out.shrink_to_fit();
|
||||
// return out;
|
||||
// }
|
||||
// }
|
||||
|
||||
namespace Tools {
|
||||
|
||||
size_t wide_ulen(const std::string_view str) {
|
||||
unsigned int chars = 0;
|
||||
try {
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
|
||||
auto w_str = conv.from_bytes((str.size() > 10000 ? str.substr(0, 10000).data() : str.data()));
|
||||
|
||||
for (auto c : w_str) {
|
||||
chars += utf8::wcwidth(c);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
return ulen(str);
|
||||
}
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
size_t wide_ulen(const std::wstring_view w_str) {
|
||||
unsigned int chars = 0;
|
||||
|
||||
for (auto c : w_str) {
|
||||
chars += utf8::wcwidth(c);
|
||||
}
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
string uresize(string str, const size_t len, bool wide) {
|
||||
if (len < 1 or str.empty())
|
||||
return "";
|
||||
|
||||
if (wide) {
|
||||
try {
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
|
||||
auto w_str = conv.from_bytes((str.size() > 10000 ? str.substr(0, 10000).c_str() : str.c_str()));
|
||||
while (wide_ulen(w_str) > len)
|
||||
w_str.pop_back();
|
||||
string n_str = conv.to_bytes(w_str);
|
||||
return n_str;
|
||||
}
|
||||
catch (...) {
|
||||
return uresize(str, len, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (size_t x = 0, i = 0; i < str.size(); i++) {
|
||||
if ((static_cast<unsigned char>(str.at(i)) & 0xC0) != 0x80) x++;
|
||||
if (x >= len + 1) {
|
||||
str.resize(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
str.shrink_to_fit();
|
||||
return str;
|
||||
}
|
||||
|
||||
string luresize(string str, const size_t len, bool wide) {
|
||||
if (len < 1 or str.empty())
|
||||
return "";
|
||||
|
||||
for (size_t x = 0, last_pos = 0, i = str.size() - 1; i > 0 ; i--) {
|
||||
if (wide and static_cast<unsigned char>(str.at(i)) > 0xef) {
|
||||
x += 2;
|
||||
last_pos = max((size_t)0, i - 1);
|
||||
}
|
||||
else if ((static_cast<unsigned char>(str.at(i)) & 0xC0) != 0x80) {
|
||||
x++;
|
||||
last_pos = i;
|
||||
}
|
||||
if (x >= len) {
|
||||
str = str.substr(last_pos);
|
||||
str.shrink_to_fit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
string s_replace(const string& str, const string& from, const string& to) {
|
||||
string out = str;
|
||||
for (size_t start_pos = out.find(from); start_pos != std::string::npos; start_pos = out.find(from)) {
|
||||
out.replace(start_pos, from.length(), to);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
string_view ltrim(string_view str, const string_view t_str) {
|
||||
while (str.starts_with(t_str))
|
||||
str.remove_prefix(t_str.size());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
string_view rtrim(string_view str, const string_view t_str) {
|
||||
while (str.ends_with(t_str))
|
||||
str.remove_suffix(t_str.size());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
string ljust(string str, const size_t x, bool utf, bool wide, bool limit) {
|
||||
if (utf) {
|
||||
if (limit and ulen(str, wide) > x)
|
||||
return uresize(str, x, wide);
|
||||
|
||||
return str + string(max((int)(x - ulen(str, wide)), 0), ' ');
|
||||
}
|
||||
else {
|
||||
if (limit and str.size() > x) {
|
||||
str.resize(x);
|
||||
return str;
|
||||
}
|
||||
return str + string(max((int)(x - str.size()), 0), ' ');
|
||||
}
|
||||
}
|
||||
|
||||
string rjust(string str, const size_t x, bool utf, bool wide, bool limit) {
|
||||
if (utf) {
|
||||
if (limit and ulen(str, wide) > x)
|
||||
return uresize(str, x, wide);
|
||||
|
||||
return string(max((int)(x - ulen(str)), 0), ' ') + str;
|
||||
}
|
||||
else {
|
||||
if (limit and str.size() > x) {
|
||||
str.resize(x);
|
||||
return str;
|
||||
};
|
||||
return string(max((int)(x - str.size()), 0), ' ') + str;
|
||||
}
|
||||
}
|
||||
|
||||
string cjust(string str, const size_t x, bool utf, bool wide, bool limit) {
|
||||
if (utf) {
|
||||
if (limit and ulen(str, wide) > x)
|
||||
return uresize(str, x, wide);
|
||||
|
||||
return string(max((int)ceil((double)(x - ulen(str)) / 2), 0), ' ') + str + string(max((int)floor((double)(x - ulen(str)) / 2), 0), ' ');
|
||||
}
|
||||
else {
|
||||
if (limit and str.size() > x) {
|
||||
str.resize(x);
|
||||
return str;
|
||||
}
|
||||
return string(max((int)ceil((double)(x - str.size()) / 2), 0), ' ') + str + string(max((int)floor((double)(x - str.size()) / 2), 0), ' ');
|
||||
}
|
||||
}
|
||||
|
||||
string trans(const string& str) {
|
||||
std::string_view oldstr{str};
|
||||
string newstr;
|
||||
newstr.reserve(str.size());
|
||||
for (size_t pos; (pos = oldstr.find(' ')) != string::npos;) {
|
||||
newstr.append(oldstr.substr(0, pos));
|
||||
size_t x = 0;
|
||||
while (pos + x < oldstr.size() and oldstr.at(pos + x) == ' ') x++;
|
||||
newstr.append(Mv::r(x));
|
||||
oldstr.remove_prefix(pos + x);
|
||||
}
|
||||
return (newstr.empty()) ? str : newstr + string{oldstr};
|
||||
}
|
||||
|
||||
string sec_to_dhms(size_t seconds, bool no_days, bool no_seconds) {
|
||||
size_t days = seconds / 86400; seconds %= 86400;
|
||||
size_t hours = seconds / 3600; seconds %= 3600;
|
||||
size_t minutes = seconds / 60; seconds %= 60;
|
||||
string out = (not no_days and days > 0 ? to_string(days) + "d " : "")
|
||||
+ (hours < 10 ? "0" : "") + to_string(hours) + ':'
|
||||
+ (minutes < 10 ? "0" : "") + to_string(minutes)
|
||||
+ (not no_seconds ? ":" + string(std::cmp_less(seconds, 10) ? "0" : "") + to_string(seconds) : "");
|
||||
return out;
|
||||
}
|
||||
|
||||
string floating_humanizer(uint64_t value, bool shorten, size_t start, bool bit, bool per_second) {
|
||||
string out;
|
||||
const size_t mult = (bit) ? 8 : 1;
|
||||
|
||||
bool mega = Config::getB("base_10_sizes");
|
||||
|
||||
// Bitrates
|
||||
if(bit && per_second) {
|
||||
const auto& base_10_bitrate = Config::getS("base_10_bitrate");
|
||||
if(base_10_bitrate == "True") {
|
||||
mega = true;
|
||||
} else if(base_10_bitrate == "False") {
|
||||
mega = false;
|
||||
}
|
||||
// Default or "Auto": Uses base_10_sizes for bitrates
|
||||
}
|
||||
|
||||
// taking advantage of type deduction for array creation (since C++17)
|
||||
// combined with string literals (operator""s)
|
||||
static const array mebiUnits_bit {
|
||||
"bit"s, "Kib"s, "Mib"s,
|
||||
"Gib"s, "Tib"s, "Pib"s,
|
||||
"Eib"s, "Zib"s, "Yib"s,
|
||||
"Bib"s, "GEb"s
|
||||
};
|
||||
static const array mebiUnits_byte {
|
||||
"Byte"s, "KiB"s, "MiB"s,
|
||||
"GiB"s, "TiB"s, "PiB"s,
|
||||
"EiB"s, "ZiB"s, "YiB"s,
|
||||
"BiB"s, "GEB"s
|
||||
};
|
||||
static const array megaUnits_bit {
|
||||
"bit"s, "Kb"s, "Mb"s,
|
||||
"Gb"s, "Tb"s, "Pb"s,
|
||||
"Eb"s, "Zb"s, "Yb"s,
|
||||
"Bb"s, "Gb"s
|
||||
};
|
||||
static const array megaUnits_byte {
|
||||
"Byte"s, "KB"s, "MB"s,
|
||||
"GB"s, "TB"s, "PB"s,
|
||||
"EB"s, "ZB"s, "YB"s,
|
||||
"BB"s, "GB"s
|
||||
};
|
||||
const auto& units = (bit) ? ( mega ? megaUnits_bit : mebiUnits_bit) : ( mega ? megaUnits_byte : mebiUnits_byte);
|
||||
|
||||
value *= 100 * mult;
|
||||
|
||||
if (mega) {
|
||||
while (value >= 100000) {
|
||||
value /= 1000;
|
||||
if (value < 100) {
|
||||
out = fmt::format("{}", value);
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (value >= 102400) {
|
||||
value >>= 10;
|
||||
if (value < 100) {
|
||||
out = fmt::format("{}", value);
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = fmt::format("{}", value);
|
||||
if (not mega and out.size() == 4 and start > 0) {
|
||||
out.pop_back();
|
||||
out.insert(2, ".");
|
||||
}
|
||||
else if (out.size() == 3 and start > 0) {
|
||||
out.insert(1, ".");
|
||||
}
|
||||
else if (out.size() >= 2) {
|
||||
out.resize(out.size() - 2);
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = "0";
|
||||
}
|
||||
}
|
||||
|
||||
if (shorten) {
|
||||
auto f_pos = out.find(".");
|
||||
if (f_pos == 1 and out.size() > 3) {
|
||||
out = fmt::format("{:.1f}", stod(out));
|
||||
}
|
||||
else if (f_pos != string::npos) {
|
||||
out = fmt::format("{:.0f}", stod(out));
|
||||
}
|
||||
if (out.size() > 3) {
|
||||
out = fmt::format("{:d}.0", out[0] - '0');
|
||||
start++;
|
||||
}
|
||||
out.push_back(units[start][0]);
|
||||
}
|
||||
else out += " " + units[start];
|
||||
|
||||
if (per_second) out += (bit) ? "ps" : "/s";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string operator*(const string& str, int64_t n) {
|
||||
if (n < 1 or str.empty()) {
|
||||
return "";
|
||||
}
|
||||
else if (n == 1) {
|
||||
return str;
|
||||
}
|
||||
|
||||
string new_str;
|
||||
new_str.reserve(str.size() * n);
|
||||
|
||||
for (; n > 0; n--)
|
||||
new_str.append(str);
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
string strf_time(const string& strf) {
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
std::tm bt {};
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(localtime_r(&in_time_t, &bt), strf.c_str());
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void atomic_wait(const atomic<bool>& atom, bool old) noexcept {
|
||||
while (atom.load(std::memory_order_relaxed) == old ) busy_wait();
|
||||
}
|
||||
|
||||
void atomic_wait_for(const atomic<bool>& atom, bool old, const uint64_t wait_ms) noexcept {
|
||||
const uint64_t start_time = time_ms();
|
||||
while (atom.load(std::memory_order_relaxed) == old and (time_ms() - start_time < wait_ms)) sleep_ms(1);
|
||||
}
|
||||
|
||||
atomic_lock::atomic_lock(atomic<bool>& atom, bool wait) : atom(atom) {
|
||||
if (wait) while (not this->atom.compare_exchange_strong(this->not_true, true));
|
||||
else this->atom.store(true);
|
||||
}
|
||||
|
||||
atomic_lock::~atomic_lock() noexcept {
|
||||
this->atom.store(false);
|
||||
}
|
||||
|
||||
string readfile(const std::filesystem::path& path, const string& fallback) {
|
||||
if (not fs::exists(path)) return fallback;
|
||||
string out;
|
||||
try {
|
||||
std::ifstream file(path);
|
||||
for (string readstr; getline(file, readstr); out += readstr);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
Logger::error("readfile() : Exception when reading " + string{path} + " : " + e.what());
|
||||
return fallback;
|
||||
}
|
||||
return (out.empty() ? fallback : out);
|
||||
}
|
||||
|
||||
auto celsius_to(const long long& celsius, const string& scale) -> tuple<long long, string> {
|
||||
if (scale == "celsius")
|
||||
return {celsius, "°C"};
|
||||
else if (scale == "fahrenheit")
|
||||
return {(long long)round((double)celsius * 1.8 + 32), "°F"};
|
||||
else if (scale == "kelvin")
|
||||
return {(long long)round((double)celsius + 273.15), "K "};
|
||||
else if (scale == "rankine")
|
||||
return {(long long)round((double)celsius * 1.8 + 491.67), "°R"};
|
||||
return {0, ""};
|
||||
}
|
||||
|
||||
string hostname() {
|
||||
char host[HOST_NAME_MAX];
|
||||
gethostname(host, HOST_NAME_MAX);
|
||||
host[HOST_NAME_MAX - 1] = '\0';
|
||||
return string{host};
|
||||
}
|
||||
|
||||
string username() {
|
||||
auto user = getenv("LOGNAME");
|
||||
if (user == nullptr or strlen(user) == 0) user = getenv("USER");
|
||||
return (user != nullptr ? user : "");
|
||||
}
|
||||
|
||||
DebugTimer::DebugTimer(string name, bool start, bool delayed_report)
|
||||
: name(std::move(name)), delayed_report(delayed_report) {
|
||||
if (start)
|
||||
this->start();
|
||||
}
|
||||
|
||||
DebugTimer::~DebugTimer() {
|
||||
if (running)
|
||||
this->stop(true);
|
||||
this->force_report();
|
||||
}
|
||||
|
||||
void DebugTimer::start() {
|
||||
if (running) return;
|
||||
running = true;
|
||||
start_time = time_micros();
|
||||
}
|
||||
|
||||
void DebugTimer::stop(bool report) {
|
||||
if (not running) return;
|
||||
running = false;
|
||||
elapsed_time = time_micros() - start_time;
|
||||
if (report) this->report();
|
||||
}
|
||||
|
||||
void DebugTimer::reset(bool restart) {
|
||||
running = false;
|
||||
start_time = 0;
|
||||
elapsed_time = 0;
|
||||
if (restart) this->start();
|
||||
}
|
||||
|
||||
void DebugTimer::stop_rename_reset(const string &new_name, bool report, bool restart) {
|
||||
this->stop(report);
|
||||
name = new_name;
|
||||
this->reset(restart);
|
||||
}
|
||||
|
||||
void DebugTimer::report() {
|
||||
string report_line;
|
||||
if (start_time == 0 and elapsed_time == 0)
|
||||
report_line = fmt::format("DebugTimer::report() warning -> Timer [{}] has not been started!", name);
|
||||
else if (running)
|
||||
report_line = fmt::format(custom_locale, "Timer [{}] (running) currently at {:L} μs", name, time_micros() - start_time);
|
||||
else
|
||||
report_line = fmt::format(custom_locale, "Timer [{}] took {:L} μs", name, elapsed_time);
|
||||
|
||||
if (delayed_report)
|
||||
report_buffer.emplace_back(report_line);
|
||||
else
|
||||
Logger::log_write(log_level, report_line);
|
||||
}
|
||||
|
||||
void DebugTimer::force_report() {
|
||||
if (report_buffer.empty()) return;
|
||||
for (const auto& line : report_buffer)
|
||||
Logger::log_write(log_level, line);
|
||||
report_buffer.clear();
|
||||
}
|
||||
|
||||
uint64_t DebugTimer::elapsed() {
|
||||
if (running)
|
||||
return time_micros() - start_time;
|
||||
return elapsed_time;
|
||||
}
|
||||
|
||||
bool DebugTimer::is_running() {
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Logger {
|
||||
using namespace Tools;
|
||||
std::atomic<bool> busy (false);
|
||||
bool first = true;
|
||||
const string tdf = "%Y/%m/%d (%T) | ";
|
||||
|
||||
size_t loglevel;
|
||||
std::optional<std::filesystem::path> logfile;
|
||||
|
||||
//* Wrapper for lowering privileges if using SUID bit and currently isn't using real userid
|
||||
class lose_priv {
|
||||
int status = -1;
|
||||
public:
|
||||
lose_priv() {
|
||||
if (geteuid() != Global::real_uid) {
|
||||
this->status = seteuid(Global::real_uid);
|
||||
}
|
||||
}
|
||||
~lose_priv() noexcept {
|
||||
if (status == 0) {
|
||||
status = seteuid(Global::set_uid);
|
||||
}
|
||||
}
|
||||
lose_priv(const lose_priv& other) = delete;
|
||||
lose_priv& operator=(const lose_priv& other) = delete;
|
||||
lose_priv(lose_priv&& other) = delete;
|
||||
lose_priv& operator=(lose_priv&& other) = delete;
|
||||
};
|
||||
|
||||
void set(const string& level) {
|
||||
loglevel = v_index(log_levels, level);
|
||||
}
|
||||
|
||||
void log_write(const Level level, const std::string_view msg) {
|
||||
if (loglevel < level or !logfile.has_value()) {
|
||||
return;
|
||||
}
|
||||
auto& log_file = logfile.value();
|
||||
atomic_lock lck(busy, true);
|
||||
lose_priv neutered{};
|
||||
std::error_code ec;
|
||||
try {
|
||||
// NOTE: `exist()` could throw but since we return with an empty logfile we don't care
|
||||
if (fs::exists(log_file) and fs::file_size(log_file, ec) > 1024 << 10 and not ec) {
|
||||
auto old_log = log_file;
|
||||
old_log += ".1";
|
||||
|
||||
if (fs::exists(old_log))
|
||||
fs::remove(old_log, ec);
|
||||
|
||||
if (not ec)
|
||||
fs::rename(log_file, old_log, ec);
|
||||
}
|
||||
if (not ec) {
|
||||
std::ofstream lwrite(log_file, std::ios::app);
|
||||
if (first) {
|
||||
first = false;
|
||||
lwrite << "\n" << strf_time(tdf) << "===> btop++ v." << Global::Version << "\n";
|
||||
}
|
||||
lwrite << strf_time(tdf) << log_levels.at(level) << ": " << msg << "\n";
|
||||
}
|
||||
else log_file.clear();
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
log_file.clear();
|
||||
throw std::runtime_error("Exception in Logger::log_write() : " + string{e.what()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,488 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
# define BTOP_DEBUG
|
||||
#endif
|
||||
|
||||
#include <algorithm> // for std::ranges::count_if
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <ranges>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#ifdef BTOP_DEBUG
|
||||
#include <source_location>
|
||||
#endif
|
||||
#ifndef HOST_NAME_MAX
|
||||
#ifdef __APPLE__
|
||||
#define HOST_NAME_MAX 255
|
||||
#else
|
||||
#define HOST_NAME_MAX 64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::string;
|
||||
using std::to_string;
|
||||
using std::string_view;
|
||||
using std::tuple;
|
||||
using std::vector;
|
||||
using namespace fmt::literals;
|
||||
|
||||
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
||||
|
||||
//* Collection of escape codes for text style and formatting
|
||||
namespace Fx {
|
||||
const string e = "\x1b["; //* Escape sequence start
|
||||
const string b = e + "1m"; //* Bold on/off
|
||||
const string ub = e + "22m"; //* Bold off
|
||||
const string d = e + "2m"; //* Dark on
|
||||
const string ud = e + "22m"; //* Dark off
|
||||
const string i = e + "3m"; //* Italic on
|
||||
const string ui = e + "23m"; //* Italic off
|
||||
const string ul = e + "4m"; //* Underline on
|
||||
const string uul = e + "24m"; //* Underline off
|
||||
const string bl = e + "5m"; //* Blink on
|
||||
const string ubl = e + "25m"; //* Blink off
|
||||
const string s = e + "9m"; //* Strike/crossed-out on
|
||||
const string us = e + "29m"; //* Strike/crossed-out on/off
|
||||
|
||||
//* Reset foreground/background color and text effects
|
||||
const string reset_base = e + "0m";
|
||||
|
||||
//* Reset text effects and restore theme foregrund and background color
|
||||
extern string reset;
|
||||
|
||||
//* Regex for matching color, style and cursor move escape sequences
|
||||
const std::regex escape_regex("\033\\[\\d+;?\\d?;?\\d*;?\\d*;?\\d*(m|f|s|u|C|D|A|B){1}");
|
||||
|
||||
//* Regex for matching only color and style escape sequences
|
||||
const std::regex color_regex("\033\\[\\d+;?\\d?;?\\d*;?\\d*;?\\d*(m){1}");
|
||||
|
||||
//* Return a string with all colors and text styling removed
|
||||
inline string uncolor(const string& s) { return std::regex_replace(s, color_regex, ""); }
|
||||
// string uncolor(const string& s);
|
||||
|
||||
}
|
||||
|
||||
//* Collection of escape codes and functions for cursor manipulation
|
||||
namespace Mv {
|
||||
//* Move cursor to <line>, <column>
|
||||
inline string to(int line, int col) { return Fx::e + to_string(line) + ';' + to_string(col) + 'f'; }
|
||||
|
||||
//* Move cursor right <x> columns
|
||||
inline string r(int x) { return Fx::e + to_string(x) + 'C'; }
|
||||
|
||||
//* Move cursor left <x> columns
|
||||
inline string l(int x) { return Fx::e + to_string(x) + 'D'; }
|
||||
|
||||
//* Move cursor up x lines
|
||||
inline string u(int x) { return Fx::e + to_string(x) + 'A'; }
|
||||
|
||||
//* Move cursor down x lines
|
||||
inline string d(int x) { return Fx::e + to_string(x) + 'B'; }
|
||||
|
||||
//* Save cursor position
|
||||
const string save = Fx::e + "s";
|
||||
|
||||
//* Restore saved cursor position
|
||||
const string restore = Fx::e + "u";
|
||||
}
|
||||
|
||||
//* Collection of escape codes and functions for terminal manipulation
|
||||
namespace Term {
|
||||
extern atomic<bool> initialized;
|
||||
extern atomic<int> width;
|
||||
extern atomic<int> height;
|
||||
extern string fg, bg, current_tty;
|
||||
|
||||
const string hide_cursor = Fx::e + "?25l";
|
||||
const string show_cursor = Fx::e + "?25h";
|
||||
const string alt_screen = Fx::e + "?1049h";
|
||||
const string normal_screen = Fx::e + "?1049l";
|
||||
const string clear = Fx::e + "2J" + Fx::e + "0;0f";
|
||||
const string clear_end = Fx::e + "0J";
|
||||
const string clear_begin = Fx::e + "1J";
|
||||
const string mouse_on = Fx::e + "?1002h" + Fx::e + "?1015h" + Fx::e + "?1006h"; //? Enable reporting of mouse position on click and release
|
||||
const string mouse_off = Fx::e + "?1002l" + Fx::e + "?1015l" + Fx::e + "?1006l";
|
||||
const string mouse_direct_on = Fx::e + "?1003h"; //? Enable reporting of mouse position at any movement
|
||||
const string mouse_direct_off = Fx::e + "?1003l";
|
||||
const string sync_start = Fx::e + "?2026h"; //? Start of terminal synchronized output
|
||||
const string sync_end = Fx::e + "?2026l"; //? End of terminal synchronized output
|
||||
|
||||
//* Returns true if terminal has been resized and updates width and height
|
||||
bool refresh(bool only_check=false);
|
||||
|
||||
//* Returns an array with the lowest possible width, height with current box config
|
||||
auto get_min_size(const string& boxes) -> array<int, 2>;
|
||||
|
||||
//* Check for a valid tty, save terminal options and set new options
|
||||
bool init();
|
||||
|
||||
//* Restore terminal options
|
||||
void restore();
|
||||
}
|
||||
|
||||
//* Simple logging implementation
|
||||
namespace Logger {
|
||||
const vector<string> log_levels = {
|
||||
"DISABLED",
|
||||
"ERROR",
|
||||
"WARNING",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
};
|
||||
extern std::optional<std::filesystem::path> logfile;
|
||||
|
||||
enum Level : std::uint8_t {
|
||||
DISABLED = 0,
|
||||
ERROR = 1,
|
||||
WARNING = 2,
|
||||
INFO = 3,
|
||||
DEBUG = 4,
|
||||
};
|
||||
|
||||
//* Set log level, valid arguments: "DISABLED", "ERROR", "WARNING", "INFO" and "DEBUG"
|
||||
void set(const string& level);
|
||||
|
||||
void log_write(const Level level, const std::string_view msg);
|
||||
|
||||
inline void error(const std::string_view msg) {
|
||||
log_write(ERROR, msg);
|
||||
}
|
||||
|
||||
inline void warning(const std::string_view msg) {
|
||||
log_write(WARNING, msg);
|
||||
}
|
||||
|
||||
inline void info(const std::string_view msg) {
|
||||
log_write(INFO, msg);
|
||||
}
|
||||
|
||||
inline void debug(const std::string_view msg) {
|
||||
log_write(DEBUG, msg);
|
||||
}
|
||||
}
|
||||
|
||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
namespace Tools {
|
||||
constexpr auto SSmax = std::numeric_limits<std::streamsize>::max();
|
||||
|
||||
class MyNumPunct : public std::numpunct<char> {
|
||||
protected:
|
||||
virtual char do_thousands_sep() const override { return '\''; }
|
||||
virtual std::string do_grouping() const override { return "\03"; }
|
||||
};
|
||||
|
||||
size_t wide_ulen(const std::string_view str);
|
||||
size_t wide_ulen(const std::wstring_view w_str);
|
||||
|
||||
//* Return number of UTF8 characters in a string (wide=true for column size needed on terminal)
|
||||
inline size_t ulen(const std::string_view str, bool wide = false) {
|
||||
return (wide ? wide_ulen(str) : std::ranges::count_if(str, [](char c) { return (static_cast<unsigned char>(c) & 0xC0) != 0x80; }));
|
||||
}
|
||||
|
||||
//* Resize a string consisting of UTF8 characters (only reduces size)
|
||||
string uresize(const string str, const size_t len, bool wide = false);
|
||||
|
||||
//* Resize a string consisting of UTF8 characters from left (only reduces size)
|
||||
string luresize(const string str, const size_t len, bool wide = false);
|
||||
|
||||
//* Replace <from> in <str> with <to> and return new string
|
||||
string s_replace(const string& str, const string& from, const string& to);
|
||||
|
||||
//* Replace ascii control characters with <replacement> in <str> and return new string
|
||||
inline string replace_ascii_control(string str, const char replacement = ' ') {
|
||||
std::ranges::for_each(str, [&replacement](char& c) { if (static_cast<unsigned char>(c) < 0x20) c = replacement; });
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Capitalize <str>
|
||||
inline string capitalize(string str) {
|
||||
str.at(0) = toupper(str.at(0));
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Return <str> with only uppercase characters
|
||||
inline auto str_to_upper(string str) {
|
||||
std::ranges::for_each(str, [](auto& c) { c = ::toupper(c); } );
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Return <str> with only lowercase characters
|
||||
inline auto str_to_lower(string str) {
|
||||
std::ranges::for_each(str, [](char& c) { c = ::tolower(c); } );
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Check if vector <vec> contains value <find_val>
|
||||
template <typename T, typename T2>
|
||||
inline bool v_contains(const vector<T>& vec, const T2& find_val) {
|
||||
return std::ranges::find(vec, find_val) != vec.end();
|
||||
}
|
||||
|
||||
//* Check if string <str> contains string <find_val>, while ignoring case
|
||||
inline bool s_contains_ic(const std::string_view str, const std::string_view find_val) {
|
||||
auto it = std::search(
|
||||
str.begin(), str.end(),
|
||||
find_val.begin(), find_val.end(),
|
||||
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }
|
||||
);
|
||||
return it != str.end();
|
||||
}
|
||||
|
||||
//* Return index of <find_val> from vector <vec>, returns size of <vec> if <find_val> is not present
|
||||
template <typename T>
|
||||
inline size_t v_index(const vector<T>& vec, const T& find_val) {
|
||||
return std::ranges::distance(vec.begin(), std::ranges::find(vec, find_val));
|
||||
}
|
||||
|
||||
//* Compare <first> with all following values
|
||||
template<typename First, typename ... T>
|
||||
inline bool is_in(const First& first, const T& ... t) {
|
||||
return ((first == t) or ...);
|
||||
}
|
||||
|
||||
//* Return current time since epoch in seconds
|
||||
inline uint64_t time_s() {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Return current time since epoch in milliseconds
|
||||
inline uint64_t time_ms() {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Return current time since epoch in microseconds
|
||||
inline uint64_t time_micros() {
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Check if a string is a valid bool value
|
||||
inline bool isbool(const std::string_view str) {
|
||||
return is_in(str, "true", "false", "True", "False");
|
||||
}
|
||||
|
||||
//* Convert string to bool, returning any value not equal to "true" or "True" as false
|
||||
inline bool stobool(const std::string_view str) {
|
||||
return is_in(str, "true", "True");
|
||||
}
|
||||
|
||||
//* Check if a string is a valid integer value (only positive)
|
||||
constexpr bool isint(const std::string_view str) {
|
||||
return std::ranges::all_of(str, ::isdigit);
|
||||
}
|
||||
|
||||
//* Left-trim <t_str> from <str> and return new string
|
||||
string_view ltrim(string_view str, string_view t_str = " ");
|
||||
|
||||
//* Right-trim <t_str> from <str> and return new string
|
||||
string_view rtrim(string_view str, string_view t_str = " ");
|
||||
|
||||
//* Left/right-trim <t_str> from <str> and return new string
|
||||
inline string_view trim(string_view str, string_view t_str = " ") {
|
||||
return ltrim(rtrim(str, t_str), t_str);
|
||||
}
|
||||
|
||||
//* Split <string> at all occurrences of <delim> and return as vector of strings
|
||||
inline std::vector<std::string> ssplit(std::string_view str, char delim = ' ') {
|
||||
std::vector<std::string> result;
|
||||
std::string token;
|
||||
for (char c : str) {
|
||||
if (c == delim) {
|
||||
if (!token.empty()) { result.push_back(token); token.clear(); }
|
||||
} else { token += c; }
|
||||
}
|
||||
if (!token.empty()) result.push_back(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
//* Put current thread to sleep for <ms> milliseconds
|
||||
inline void sleep_ms(const size_t& ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
//* Put current thread to sleep for <micros> microseconds
|
||||
inline void sleep_micros(const size_t& micros) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(micros));
|
||||
}
|
||||
|
||||
//* Left justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string ljust(string str, const size_t x, bool utf = false, bool wide = false, bool limit = true);
|
||||
|
||||
//* Right justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string rjust(string str, const size_t x, bool utf = false, bool wide = false, bool limit = true);
|
||||
|
||||
//* Center justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string cjust(string str, const size_t x, bool utf = false, bool wide = false, bool limit = true);
|
||||
|
||||
//* Replace whitespaces " " with escape code for move right
|
||||
string trans(const string& str);
|
||||
|
||||
//* Convert seconds to format "<days>d <hours>:<minutes>:<seconds>" and return string
|
||||
string sec_to_dhms(size_t seconds, bool no_days = false, bool no_seconds = false);
|
||||
|
||||
//* Scales up in steps of 1024 to highest positive value unit and returns string with unit suffixed
|
||||
//* bit=True or defaults to bytes
|
||||
//* start=int to set 1024 multiplier starting unit
|
||||
//* short=True always returns 0 decimals and shortens unit to 1 character
|
||||
string floating_humanizer(uint64_t value, bool shorten = false, size_t start = 0, bool bit = false, bool per_second = false);
|
||||
|
||||
//* Add std::string operator * : Repeat string <str> <n> number of times
|
||||
std::string operator*(const string& str, int64_t n);
|
||||
|
||||
template <typename K, typename T>
|
||||
#ifdef BTOP_DEBUG
|
||||
const T& safeVal(const std::unordered_map<K, T>& map, const K& key, const T& fallback = T{}, std::source_location loc = std::source_location::current()) {
|
||||
if (auto it = map.find(key); it != map.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
Logger::error(fmt::format("safeVal() called with invalid key: [{}] in file: {} on line: {}", key, loc.file_name(), loc.line()));
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
#else
|
||||
const T& safeVal(const std::unordered_map<K, T>& map, const K& key, const T& fallback = T{}) {
|
||||
if (auto it = map.find(key); it != map.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
Logger::error(fmt::format("safeVal() called with invalid key: [{}] (Compile btop with DEBUG=true for more extensive logging!)", key));
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
#ifdef BTOP_DEBUG
|
||||
const T& safeVal(const std::vector<T>& vec, const size_t& index, const T& fallback = T{}, std::source_location loc = std::source_location::current()) {
|
||||
if (index < vec.size()) {
|
||||
return vec[index];
|
||||
} else {
|
||||
Logger::error(fmt::format("safeVal() called with invalid index: [{}] in file: {} on line: {}", index, loc.file_name(), loc.line()));
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
#else
|
||||
const T& safeVal(const std::vector<T>& vec, const size_t& index, const T& fallback = T{}) {
|
||||
if (index < vec.size()) {
|
||||
return vec[index];
|
||||
} else {
|
||||
Logger::error(fmt::format("safeVal() called with invalid index: [{}] (Compile btop with DEBUG=true for more extensive logging!)", index));
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//* Return current time in <strf> format
|
||||
string strf_time(const string& strf);
|
||||
|
||||
string hostname();
|
||||
string username();
|
||||
|
||||
static inline void busy_wait (void) {
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
__builtin_ia32_pause();
|
||||
#elif defined __ia64__
|
||||
__asm volatile("hint @pause" : : : "memory");
|
||||
#elif defined __sparc__ && (defined __arch64__ || defined __sparc_v9__)
|
||||
__asm volatile("membar #LoadLoad" : : : "memory");
|
||||
#else
|
||||
__asm volatile("" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
void atomic_wait(const atomic<bool>& atom, bool old = true) noexcept;
|
||||
|
||||
void atomic_wait_for(const atomic<bool>& atom, bool old = true, const uint64_t wait_ms = 0) noexcept;
|
||||
|
||||
//* Sets atomic<bool> to true on construct, sets to false on destruct
|
||||
class atomic_lock {
|
||||
atomic<bool>& atom;
|
||||
bool not_true{};
|
||||
public:
|
||||
explicit atomic_lock(atomic<bool>& atom, bool wait = false);
|
||||
~atomic_lock() noexcept;
|
||||
atomic_lock(const atomic_lock& other) = delete;
|
||||
atomic_lock& operator=(const atomic_lock& other) = delete;
|
||||
atomic_lock(atomic_lock&& other) = delete;
|
||||
atomic_lock& operator=(atomic_lock&& other) = delete;
|
||||
};
|
||||
|
||||
//* Read a complete file and return as a string
|
||||
string readfile(const std::filesystem::path& path, const string& fallback = "");
|
||||
|
||||
//* Convert a celsius value to celsius, fahrenheit, kelvin or rankin and return tuple with new value and unit.
|
||||
auto celsius_to(const long long& celsius, const string& scale) -> tuple<long long, string>;
|
||||
}
|
||||
|
||||
namespace Tools {
|
||||
//* Creates a named timer that is started on construct (by default) and reports elapsed time in microseconds to Logger::debug() on destruct if running
|
||||
//* Unless delayed_report is set to false, all reporting is buffered and delayed until DebugTimer is destructed or .force_report() is called
|
||||
//* Usage example: Tools::DebugTimer timer(name:"myTimer", [start:true], [delayed_report:true]) // Create timer and start
|
||||
//* timer.stop(); // Stop timer and report elapsed time
|
||||
//* timer.stop_rename_reset("myTimer2"); // Stop timer, report elapsed time, rename timer, reset and restart
|
||||
class DebugTimer {
|
||||
uint64_t start_time{};
|
||||
uint64_t elapsed_time{};
|
||||
bool running{};
|
||||
std::locale custom_locale = std::locale(std::locale::classic(), new Tools::MyNumPunct);
|
||||
vector<string> report_buffer{};
|
||||
string name{};
|
||||
bool delayed_report{};
|
||||
Logger::Level log_level = Logger::DEBUG;
|
||||
public:
|
||||
DebugTimer() = default;
|
||||
explicit DebugTimer(string name, bool start = true, bool delayed_report = true);
|
||||
~DebugTimer();
|
||||
DebugTimer(const DebugTimer& other) = delete;
|
||||
DebugTimer& operator=(const DebugTimer& other) = delete;
|
||||
DebugTimer(DebugTimer&& other) = delete;
|
||||
DebugTimer& operator=(DebugTimer&& other) = delete;
|
||||
|
||||
void start();
|
||||
void stop(bool report = true);
|
||||
void reset(bool restart = true);
|
||||
//* Stops and reports (default), renames timer then resets and restarts (default)
|
||||
void stop_rename_reset(const string& new_name, bool report = true, bool restart = true);
|
||||
void report();
|
||||
void force_report();
|
||||
uint64_t elapsed();
|
||||
bool is_running();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
constexpr std::string_view GIT_COMMIT = "@GIT_COMMIT@";
|
||||
constexpr std::string_view COMPILER = "@COMPILER@";
|
||||
constexpr std::string_view COMPILER_VERSION = "@COMPILER_VERSION@";
|
||||
constexpr std::string_view CONFIGURE_COMMAND = "@CONFIGURE_COMMAND@";
|
||||
1356
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/freebsd/btop_collect.cpp
vendored
Normal file
1356
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/freebsd/btop_collect.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3122
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/btop_collect.cpp
vendored
Normal file
3122
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/btop_collect.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/CMakeLists.txt
vendored
Normal file
19
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
enable_language(C)
|
||||
|
||||
add_library(igt OBJECT
|
||||
igt_perf.c
|
||||
intel_device_info.c
|
||||
intel_gpu_top.c
|
||||
intel_name_lookup_shim.c
|
||||
)
|
||||
|
||||
if(BTOP_LTO)
|
||||
# We have checked LTO support already and it's supported :)
|
||||
set_target_properties(igt PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
|
||||
endif()
|
||||
|
||||
# Disable all warnings
|
||||
target_compile_options(igt PRIVATE -w)
|
||||
|
||||
# Link igt into btop
|
||||
target_link_libraries(libbtop $<TARGET_OBJECTS:igt>)
|
||||
1318
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/drm.h
vendored
Normal file
1318
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/drm.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1318
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/drm_mode.h
vendored
Normal file
1318
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/drm_mode.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3860
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/i915_drm.h
vendored
Normal file
3860
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/i915_drm.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
786
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/i915_pciids.h
vendored
Normal file
786
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/i915_pciids.h
vendored
Normal file
|
|
@ -0,0 +1,786 @@
|
|||
/*
|
||||
* Copyright 2013 Intel Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _I915_PCIIDS_H
|
||||
#define _I915_PCIIDS_H
|
||||
|
||||
/*
|
||||
* A pci_device_id struct {
|
||||
* __u32 vendor, device;
|
||||
* __u32 subvendor, subdevice;
|
||||
* __u32 class, class_mask;
|
||||
* kernel_ulong_t driver_data;
|
||||
* };
|
||||
* Don't use C99 here because "class" is reserved and we want to
|
||||
* give userspace flexibility.
|
||||
*/
|
||||
#define INTEL_VGA_DEVICE(id, info) { \
|
||||
0x8086, id, \
|
||||
~0, ~0, \
|
||||
0x030000, 0xff0000, \
|
||||
(unsigned long) info }
|
||||
|
||||
#define INTEL_QUANTA_VGA_DEVICE(info) { \
|
||||
0x8086, 0x16a, \
|
||||
0x152d, 0x8990, \
|
||||
0x030000, 0xff0000, \
|
||||
(unsigned long) info }
|
||||
|
||||
#define INTEL_I810_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7121, ## __VA_ARGS__), /* I810 */ \
|
||||
MACRO__(0x7123, ## __VA_ARGS__), /* I810_DC100 */ \
|
||||
MACRO__(0x7125, ## __VA_ARGS__) /* I810_E */
|
||||
|
||||
#define INTEL_I815_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1132, ## __VA_ARGS__) /* I815*/
|
||||
|
||||
#define INTEL_I830_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3577, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_I845G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2562, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_I85X_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3582, ## __VA_ARGS__), /* I855_GM */ \
|
||||
MACRO__(0x358e, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_I865G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2572, ## __VA_ARGS__) /* I865_G */
|
||||
|
||||
#define INTEL_I915G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2582, ## __VA_ARGS__), /* I915_G */ \
|
||||
MACRO__(0x258a, ## __VA_ARGS__) /* E7221_G */
|
||||
|
||||
#define INTEL_I915GM_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2592, ## __VA_ARGS__) /* I915_GM */
|
||||
|
||||
#define INTEL_I945G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2772, ## __VA_ARGS__) /* I945_G */
|
||||
|
||||
#define INTEL_I945GM_IDS(MACRO__, ...) \
|
||||
MACRO__(0x27a2, ## __VA_ARGS__), /* I945_GM */ \
|
||||
MACRO__(0x27ae, ## __VA_ARGS__) /* I945_GME */
|
||||
|
||||
#define INTEL_I965G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2972, ## __VA_ARGS__), /* I946_GZ */ \
|
||||
MACRO__(0x2982, ## __VA_ARGS__), /* G35_G */ \
|
||||
MACRO__(0x2992, ## __VA_ARGS__), /* I965_Q */ \
|
||||
MACRO__(0x29a2, ## __VA_ARGS__) /* I965_G */
|
||||
|
||||
#define INTEL_G33_IDS(MACRO__, ...) \
|
||||
MACRO__(0x29b2, ## __VA_ARGS__), /* Q35_G */ \
|
||||
MACRO__(0x29c2, ## __VA_ARGS__), /* G33_G */ \
|
||||
MACRO__(0x29d2, ## __VA_ARGS__) /* Q33_G */
|
||||
|
||||
#define INTEL_I965GM_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2a02, ## __VA_ARGS__), /* I965_GM */ \
|
||||
MACRO__(0x2a12, ## __VA_ARGS__) /* I965_GME */
|
||||
|
||||
#define INTEL_GM45_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2a42, ## __VA_ARGS__) /* GM45_G */
|
||||
|
||||
#define INTEL_G45_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2e02, ## __VA_ARGS__), /* IGD_E_G */ \
|
||||
MACRO__(0x2e12, ## __VA_ARGS__), /* Q45_G */ \
|
||||
MACRO__(0x2e22, ## __VA_ARGS__), /* G45_G */ \
|
||||
MACRO__(0x2e32, ## __VA_ARGS__), /* G41_G */ \
|
||||
MACRO__(0x2e42, ## __VA_ARGS__), /* B43_G */ \
|
||||
MACRO__(0x2e92, ## __VA_ARGS__) /* B43_G.1 */
|
||||
|
||||
#define INTEL_PNV_G_IDS(MACRO__, ...) \
|
||||
MACRO__(0xa001, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_PNV_M_IDS(MACRO__, ...) \
|
||||
MACRO__(0xa011, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_PNV_IDS(MACRO__, ...) \
|
||||
INTEL_PNV_G_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_PNV_M_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ILK_D_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0042, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ILK_M_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0046, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ILK_IDS(MACRO__, ...) \
|
||||
INTEL_ILK_D_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_ILK_M_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_D_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0102, ## __VA_ARGS__), \
|
||||
MACRO__(0x010A, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_D_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0112, ## __VA_ARGS__), \
|
||||
MACRO__(0x0122, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_D_IDS(MACRO__, ...) \
|
||||
INTEL_SNB_D_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SNB_D_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_M_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0106, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_M_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0116, ## __VA_ARGS__), \
|
||||
MACRO__(0x0126, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_M_IDS(MACRO__, ...) \
|
||||
INTEL_SNB_M_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SNB_M_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_IDS(MACRO__, ...) \
|
||||
INTEL_SNB_D_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SNB_M_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_IVB_M_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0156, ## __VA_ARGS__) /* GT1 mobile */
|
||||
|
||||
#define INTEL_IVB_M_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0166, ## __VA_ARGS__) /* GT2 mobile */
|
||||
|
||||
#define INTEL_IVB_M_IDS(MACRO__, ...) \
|
||||
INTEL_IVB_M_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_IVB_M_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_IVB_D_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0152, ## __VA_ARGS__), /* GT1 desktop */ \
|
||||
MACRO__(0x015a, ## __VA_ARGS__) /* GT1 server */
|
||||
|
||||
#define INTEL_IVB_D_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0162, ## __VA_ARGS__), /* GT2 desktop */ \
|
||||
MACRO__(0x016a, ## __VA_ARGS__) /* GT2 server */
|
||||
|
||||
#define INTEL_IVB_D_IDS(MACRO__, ...) \
|
||||
INTEL_IVB_D_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_IVB_D_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_IVB_IDS(MACRO__, ...) \
|
||||
INTEL_IVB_M_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_IVB_D_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_IVB_Q_IDS(MACRO__, ...) \
|
||||
INTEL_QUANTA_VGA_DEVICE(__VA_ARGS__) /* Quanta transcode */
|
||||
|
||||
#define INTEL_HSW_ULT_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A02, ## __VA_ARGS__), /* ULT GT1 desktop */ \
|
||||
MACRO__(0x0A06, ## __VA_ARGS__), /* ULT GT1 mobile */ \
|
||||
MACRO__(0x0A0A, ## __VA_ARGS__), /* ULT GT1 server */ \
|
||||
MACRO__(0x0A0B, ## __VA_ARGS__) /* ULT GT1 reserved */
|
||||
|
||||
#define INTEL_HSW_ULX_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A0E, ## __VA_ARGS__) /* ULX GT1 mobile */
|
||||
|
||||
#define INTEL_HSW_GT1_IDS(MACRO__, ...) \
|
||||
INTEL_HSW_ULT_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_HSW_ULX_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x0402, ## __VA_ARGS__), /* GT1 desktop */ \
|
||||
MACRO__(0x0406, ## __VA_ARGS__), /* GT1 mobile */ \
|
||||
MACRO__(0x040A, ## __VA_ARGS__), /* GT1 server */ \
|
||||
MACRO__(0x040B, ## __VA_ARGS__), /* GT1 reserved */ \
|
||||
MACRO__(0x040E, ## __VA_ARGS__), /* GT1 reserved */ \
|
||||
MACRO__(0x0C02, ## __VA_ARGS__), /* SDV GT1 desktop */ \
|
||||
MACRO__(0x0C06, ## __VA_ARGS__), /* SDV GT1 mobile */ \
|
||||
MACRO__(0x0C0A, ## __VA_ARGS__), /* SDV GT1 server */ \
|
||||
MACRO__(0x0C0B, ## __VA_ARGS__), /* SDV GT1 reserved */ \
|
||||
MACRO__(0x0C0E, ## __VA_ARGS__), /* SDV GT1 reserved */ \
|
||||
MACRO__(0x0D02, ## __VA_ARGS__), /* CRW GT1 desktop */ \
|
||||
MACRO__(0x0D06, ## __VA_ARGS__), /* CRW GT1 mobile */ \
|
||||
MACRO__(0x0D0A, ## __VA_ARGS__), /* CRW GT1 server */ \
|
||||
MACRO__(0x0D0B, ## __VA_ARGS__), /* CRW GT1 reserved */ \
|
||||
MACRO__(0x0D0E, ## __VA_ARGS__) /* CRW GT1 reserved */
|
||||
|
||||
#define INTEL_HSW_ULT_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A12, ## __VA_ARGS__), /* ULT GT2 desktop */ \
|
||||
MACRO__(0x0A16, ## __VA_ARGS__), /* ULT GT2 mobile */ \
|
||||
MACRO__(0x0A1A, ## __VA_ARGS__), /* ULT GT2 server */ \
|
||||
MACRO__(0x0A1B, ## __VA_ARGS__) /* ULT GT2 reserved */ \
|
||||
|
||||
#define INTEL_HSW_ULX_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A1E, ## __VA_ARGS__) /* ULX GT2 mobile */ \
|
||||
|
||||
#define INTEL_HSW_GT2_IDS(MACRO__, ...) \
|
||||
INTEL_HSW_ULT_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_HSW_ULX_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x0412, ## __VA_ARGS__), /* GT2 desktop */ \
|
||||
MACRO__(0x0416, ## __VA_ARGS__), /* GT2 mobile */ \
|
||||
MACRO__(0x041A, ## __VA_ARGS__), /* GT2 server */ \
|
||||
MACRO__(0x041B, ## __VA_ARGS__), /* GT2 reserved */ \
|
||||
MACRO__(0x041E, ## __VA_ARGS__), /* GT2 reserved */ \
|
||||
MACRO__(0x0C12, ## __VA_ARGS__), /* SDV GT2 desktop */ \
|
||||
MACRO__(0x0C16, ## __VA_ARGS__), /* SDV GT2 mobile */ \
|
||||
MACRO__(0x0C1A, ## __VA_ARGS__), /* SDV GT2 server */ \
|
||||
MACRO__(0x0C1B, ## __VA_ARGS__), /* SDV GT2 reserved */ \
|
||||
MACRO__(0x0C1E, ## __VA_ARGS__), /* SDV GT2 reserved */ \
|
||||
MACRO__(0x0D12, ## __VA_ARGS__), /* CRW GT2 desktop */ \
|
||||
MACRO__(0x0D16, ## __VA_ARGS__), /* CRW GT2 mobile */ \
|
||||
MACRO__(0x0D1A, ## __VA_ARGS__), /* CRW GT2 server */ \
|
||||
MACRO__(0x0D1B, ## __VA_ARGS__), /* CRW GT2 reserved */ \
|
||||
MACRO__(0x0D1E, ## __VA_ARGS__) /* CRW GT2 reserved */
|
||||
|
||||
#define INTEL_HSW_ULT_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A22, ## __VA_ARGS__), /* ULT GT3 desktop */ \
|
||||
MACRO__(0x0A26, ## __VA_ARGS__), /* ULT GT3 mobile */ \
|
||||
MACRO__(0x0A2A, ## __VA_ARGS__), /* ULT GT3 server */ \
|
||||
MACRO__(0x0A2B, ## __VA_ARGS__), /* ULT GT3 reserved */ \
|
||||
MACRO__(0x0A2E, ## __VA_ARGS__) /* ULT GT3 reserved */
|
||||
|
||||
#define INTEL_HSW_GT3_IDS(MACRO__, ...) \
|
||||
INTEL_HSW_ULT_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x0422, ## __VA_ARGS__), /* GT3 desktop */ \
|
||||
MACRO__(0x0426, ## __VA_ARGS__), /* GT3 mobile */ \
|
||||
MACRO__(0x042A, ## __VA_ARGS__), /* GT3 server */ \
|
||||
MACRO__(0x042B, ## __VA_ARGS__), /* GT3 reserved */ \
|
||||
MACRO__(0x042E, ## __VA_ARGS__), /* GT3 reserved */ \
|
||||
MACRO__(0x0C22, ## __VA_ARGS__), /* SDV GT3 desktop */ \
|
||||
MACRO__(0x0C26, ## __VA_ARGS__), /* SDV GT3 mobile */ \
|
||||
MACRO__(0x0C2A, ## __VA_ARGS__), /* SDV GT3 server */ \
|
||||
MACRO__(0x0C2B, ## __VA_ARGS__), /* SDV GT3 reserved */ \
|
||||
MACRO__(0x0C2E, ## __VA_ARGS__), /* SDV GT3 reserved */ \
|
||||
MACRO__(0x0D22, ## __VA_ARGS__), /* CRW GT3 desktop */ \
|
||||
MACRO__(0x0D26, ## __VA_ARGS__), /* CRW GT3 mobile */ \
|
||||
MACRO__(0x0D2A, ## __VA_ARGS__), /* CRW GT3 server */ \
|
||||
MACRO__(0x0D2B, ## __VA_ARGS__), /* CRW GT3 reserved */ \
|
||||
MACRO__(0x0D2E, ## __VA_ARGS__) /* CRW GT3 reserved */
|
||||
|
||||
#define INTEL_HSW_IDS(MACRO__, ...) \
|
||||
INTEL_HSW_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_HSW_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_HSW_GT3_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_VLV_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0f30, ## __VA_ARGS__), \
|
||||
MACRO__(0x0f31, ## __VA_ARGS__), \
|
||||
MACRO__(0x0f32, ## __VA_ARGS__), \
|
||||
MACRO__(0x0f33, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_BDW_ULT_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1606, ## __VA_ARGS__), /* GT1 ULT */ \
|
||||
MACRO__(0x160B, ## __VA_ARGS__) /* GT1 Iris */
|
||||
|
||||
#define INTEL_BDW_ULX_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x160E, ## __VA_ARGS__) /* GT1 ULX */
|
||||
|
||||
#define INTEL_BDW_GT1_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_ULT_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_ULX_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1602, ## __VA_ARGS__), /* GT1 ULT */ \
|
||||
MACRO__(0x160A, ## __VA_ARGS__), /* GT1 Server */ \
|
||||
MACRO__(0x160D, ## __VA_ARGS__) /* GT1 Workstation */
|
||||
|
||||
#define INTEL_BDW_ULT_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1616, ## __VA_ARGS__), /* GT2 ULT */ \
|
||||
MACRO__(0x161B, ## __VA_ARGS__) /* GT2 ULT */
|
||||
|
||||
#define INTEL_BDW_ULX_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x161E, ## __VA_ARGS__) /* GT2 ULX */
|
||||
|
||||
#define INTEL_BDW_GT2_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_ULT_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_ULX_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1612, ## __VA_ARGS__), /* GT2 Halo */ \
|
||||
MACRO__(0x161A, ## __VA_ARGS__), /* GT2 Server */ \
|
||||
MACRO__(0x161D, ## __VA_ARGS__) /* GT2 Workstation */
|
||||
|
||||
#define INTEL_BDW_ULT_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1626, ## __VA_ARGS__), /* ULT */ \
|
||||
MACRO__(0x162B, ## __VA_ARGS__) /* Iris */ \
|
||||
|
||||
#define INTEL_BDW_ULX_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x162E, ## __VA_ARGS__) /* ULX */
|
||||
|
||||
#define INTEL_BDW_GT3_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_ULT_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_ULX_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1622, ## __VA_ARGS__), /* ULT */ \
|
||||
MACRO__(0x162A, ## __VA_ARGS__), /* Server */ \
|
||||
MACRO__(0x162D, ## __VA_ARGS__) /* Workstation */
|
||||
|
||||
#define INTEL_BDW_ULT_RSVD_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1636, ## __VA_ARGS__), /* ULT */ \
|
||||
MACRO__(0x163B, ## __VA_ARGS__) /* Iris */
|
||||
|
||||
#define INTEL_BDW_ULX_RSVD_IDS(MACRO__, ...) \
|
||||
MACRO__(0x163E, ## __VA_ARGS__) /* ULX */
|
||||
|
||||
#define INTEL_BDW_RSVD_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_ULT_RSVD_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_ULX_RSVD_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1632, ## __VA_ARGS__), /* ULT */ \
|
||||
MACRO__(0x163A, ## __VA_ARGS__), /* Server */ \
|
||||
MACRO__(0x163D, ## __VA_ARGS__) /* Workstation */
|
||||
|
||||
#define INTEL_BDW_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_RSVD_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CHV_IDS(MACRO__, ...) \
|
||||
MACRO__(0x22b0, ## __VA_ARGS__), \
|
||||
MACRO__(0x22b1, ## __VA_ARGS__), \
|
||||
MACRO__(0x22b2, ## __VA_ARGS__), \
|
||||
MACRO__(0x22b3, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SKL_ULT_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1906, ## __VA_ARGS__), /* ULT GT1 */ \
|
||||
MACRO__(0x1913, ## __VA_ARGS__) /* ULT GT1.5 */
|
||||
|
||||
#define INTEL_SKL_ULX_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x190E, ## __VA_ARGS__), /* ULX GT1 */ \
|
||||
MACRO__(0x1915, ## __VA_ARGS__) /* ULX GT1.5 */
|
||||
|
||||
#define INTEL_SKL_GT1_IDS(MACRO__, ...) \
|
||||
INTEL_SKL_ULT_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_ULX_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1902, ## __VA_ARGS__), /* DT GT1 */ \
|
||||
MACRO__(0x190A, ## __VA_ARGS__), /* SRV GT1 */ \
|
||||
MACRO__(0x190B, ## __VA_ARGS__), /* Halo GT1 */ \
|
||||
MACRO__(0x1917, ## __VA_ARGS__) /* DT GT1.5 */
|
||||
|
||||
#define INTEL_SKL_ULT_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1916, ## __VA_ARGS__), /* ULT GT2 */ \
|
||||
MACRO__(0x1921, ## __VA_ARGS__) /* ULT GT2F */
|
||||
|
||||
#define INTEL_SKL_ULX_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x191E, ## __VA_ARGS__) /* ULX GT2 */
|
||||
|
||||
#define INTEL_SKL_GT2_IDS(MACRO__, ...) \
|
||||
INTEL_SKL_ULT_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_ULX_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1912, ## __VA_ARGS__), /* DT GT2 */ \
|
||||
MACRO__(0x191A, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x191B, ## __VA_ARGS__), /* Halo GT2 */ \
|
||||
MACRO__(0x191D, ## __VA_ARGS__) /* WKS GT2 */
|
||||
|
||||
#define INTEL_SKL_ULT_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1923, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x1926, ## __VA_ARGS__), /* ULT GT3e */ \
|
||||
MACRO__(0x1927, ## __VA_ARGS__) /* ULT GT3e */
|
||||
|
||||
#define INTEL_SKL_GT3_IDS(MACRO__, ...) \
|
||||
INTEL_SKL_ULT_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x192A, ## __VA_ARGS__), /* SRV GT3 */ \
|
||||
MACRO__(0x192B, ## __VA_ARGS__), /* Halo GT3e */ \
|
||||
MACRO__(0x192D, ## __VA_ARGS__) /* SRV GT3e */
|
||||
|
||||
#define INTEL_SKL_GT4_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1932, ## __VA_ARGS__), /* DT GT4 */ \
|
||||
MACRO__(0x193A, ## __VA_ARGS__), /* SRV GT4e */ \
|
||||
MACRO__(0x193B, ## __VA_ARGS__), /* Halo GT4e */ \
|
||||
MACRO__(0x193D, ## __VA_ARGS__) /* WKS GT4e */
|
||||
|
||||
#define INTEL_SKL_IDS(MACRO__, ...) \
|
||||
INTEL_SKL_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_GT4_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_BXT_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A84, ## __VA_ARGS__), \
|
||||
MACRO__(0x1A84, ## __VA_ARGS__), \
|
||||
MACRO__(0x1A85, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A84, ## __VA_ARGS__), /* APL HD Graphics 505 */ \
|
||||
MACRO__(0x5A85, ## __VA_ARGS__) /* APL HD Graphics 500 */
|
||||
|
||||
#define INTEL_GLK_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3184, ## __VA_ARGS__), \
|
||||
MACRO__(0x3185, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_KBL_ULT_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5906, ## __VA_ARGS__), /* ULT GT1 */ \
|
||||
MACRO__(0x5913, ## __VA_ARGS__) /* ULT GT1.5 */
|
||||
|
||||
#define INTEL_KBL_ULX_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x590E, ## __VA_ARGS__), /* ULX GT1 */ \
|
||||
MACRO__(0x5915, ## __VA_ARGS__) /* ULX GT1.5 */
|
||||
|
||||
#define INTEL_KBL_GT1_IDS(MACRO__, ...) \
|
||||
INTEL_KBL_ULT_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_ULX_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x5902, ## __VA_ARGS__), /* DT GT1 */ \
|
||||
MACRO__(0x5908, ## __VA_ARGS__), /* Halo GT1 */ \
|
||||
MACRO__(0x590A, ## __VA_ARGS__), /* SRV GT1 */ \
|
||||
MACRO__(0x590B, ## __VA_ARGS__) /* Halo GT1 */
|
||||
|
||||
#define INTEL_KBL_ULT_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5916, ## __VA_ARGS__), /* ULT GT2 */ \
|
||||
MACRO__(0x5921, ## __VA_ARGS__) /* ULT GT2F */
|
||||
|
||||
#define INTEL_KBL_ULX_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x591E, ## __VA_ARGS__) /* ULX GT2 */
|
||||
|
||||
#define INTEL_KBL_GT2_IDS(MACRO__, ...) \
|
||||
INTEL_KBL_ULT_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_ULX_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x5912, ## __VA_ARGS__), /* DT GT2 */ \
|
||||
MACRO__(0x5917, ## __VA_ARGS__), /* Mobile GT2 */ \
|
||||
MACRO__(0x591A, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x591B, ## __VA_ARGS__), /* Halo GT2 */ \
|
||||
MACRO__(0x591D, ## __VA_ARGS__) /* WKS GT2 */
|
||||
|
||||
#define INTEL_KBL_ULT_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5926, ## __VA_ARGS__) /* ULT GT3 */
|
||||
|
||||
#define INTEL_KBL_GT3_IDS(MACRO__, ...) \
|
||||
INTEL_KBL_ULT_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x5923, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x5927, ## __VA_ARGS__) /* ULT GT3 */
|
||||
|
||||
#define INTEL_KBL_GT4_IDS(MACRO__, ...) \
|
||||
MACRO__(0x593B, ## __VA_ARGS__) /* Halo GT4 */
|
||||
|
||||
/* AML/KBL Y GT2 */
|
||||
#define INTEL_AML_KBL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x591C, ## __VA_ARGS__), /* ULX GT2 */ \
|
||||
MACRO__(0x87C0, ## __VA_ARGS__) /* ULX GT2 */
|
||||
|
||||
/* AML/CFL Y GT2 */
|
||||
#define INTEL_AML_CFL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x87CA, ## __VA_ARGS__)
|
||||
|
||||
/* CML GT1 */
|
||||
#define INTEL_CML_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9BA2, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BA4, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BA5, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BA8, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CML_U_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9B21, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BAA, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BAC, ## __VA_ARGS__)
|
||||
|
||||
/* CML GT2 */
|
||||
#define INTEL_CML_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9BC2, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BC4, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BC5, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BC6, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BC8, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BE6, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BF6, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CML_U_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9B41, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BCA, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BCC, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CML_IDS(MACRO__, ...) \
|
||||
INTEL_CML_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CML_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CML_U_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CML_U_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_KBL_IDS(MACRO__, ...) \
|
||||
INTEL_KBL_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_GT4_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_AML_KBL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* CFL S */
|
||||
#define INTEL_CFL_S_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3E90, ## __VA_ARGS__), /* SRV GT1 */ \
|
||||
MACRO__(0x3E93, ## __VA_ARGS__), /* SRV GT1 */ \
|
||||
MACRO__(0x3E99, ## __VA_ARGS__) /* SRV GT1 */
|
||||
|
||||
#define INTEL_CFL_S_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3E91, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x3E92, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x3E96, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x3E98, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x3E9A, ## __VA_ARGS__) /* SRV GT2 */
|
||||
|
||||
/* CFL H */
|
||||
#define INTEL_CFL_H_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3E9C, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CFL_H_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3E94, ## __VA_ARGS__), /* Halo GT2 */ \
|
||||
MACRO__(0x3E9B, ## __VA_ARGS__) /* Halo GT2 */
|
||||
|
||||
/* CFL U GT2 */
|
||||
#define INTEL_CFL_U_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA9, ## __VA_ARGS__)
|
||||
|
||||
/* CFL U GT3 */
|
||||
#define INTEL_CFL_U_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA5, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x3EA6, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x3EA7, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x3EA8, ## __VA_ARGS__) /* ULT GT3 */
|
||||
|
||||
#define INTEL_CFL_IDS(MACRO__, ...) \
|
||||
INTEL_CFL_S_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_S_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_H_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_H_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_U_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_U_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_AML_CFL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* WHL/CFL U GT1 */
|
||||
#define INTEL_WHL_U_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA1, ## __VA_ARGS__), \
|
||||
MACRO__(0x3EA4, ## __VA_ARGS__)
|
||||
|
||||
/* WHL/CFL U GT2 */
|
||||
#define INTEL_WHL_U_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA0, ## __VA_ARGS__), \
|
||||
MACRO__(0x3EA3, ## __VA_ARGS__)
|
||||
|
||||
/* WHL/CFL U GT3 */
|
||||
#define INTEL_WHL_U_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA2, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_WHL_IDS(MACRO__, ...) \
|
||||
INTEL_WHL_U_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_WHL_U_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_WHL_U_GT3_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* CNL */
|
||||
#define INTEL_CNL_PORT_F_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5A44, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A4C, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A54, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A5C, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CNL_IDS(MACRO__, ...) \
|
||||
INTEL_CNL_PORT_F_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A40, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A41, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A42, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A49, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A4A, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A50, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A51, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A52, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A59, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A5A, ## __VA_ARGS__)
|
||||
|
||||
/* ICL */
|
||||
#define INTEL_ICL_PORT_F_IDS(MACRO__, ...) \
|
||||
MACRO__(0x8A50, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A52, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A53, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A54, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A56, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A57, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A58, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A59, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A5A, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A5B, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A5C, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A70, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A71, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ICL_IDS(MACRO__, ...) \
|
||||
INTEL_ICL_PORT_F_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A51, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A5D, ## __VA_ARGS__)
|
||||
|
||||
/* EHL */
|
||||
#define INTEL_EHL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4541, ## __VA_ARGS__), \
|
||||
MACRO__(0x4551, ## __VA_ARGS__), \
|
||||
MACRO__(0x4555, ## __VA_ARGS__), \
|
||||
MACRO__(0x4557, ## __VA_ARGS__), \
|
||||
MACRO__(0x4570, ## __VA_ARGS__), \
|
||||
MACRO__(0x4571, ## __VA_ARGS__)
|
||||
|
||||
/* JSL */
|
||||
#define INTEL_JSL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4E51, ## __VA_ARGS__), \
|
||||
MACRO__(0x4E55, ## __VA_ARGS__), \
|
||||
MACRO__(0x4E57, ## __VA_ARGS__), \
|
||||
MACRO__(0x4E61, ## __VA_ARGS__), \
|
||||
MACRO__(0x4E71, ## __VA_ARGS__)
|
||||
|
||||
/* TGL */
|
||||
#define INTEL_TGL_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9A60, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A68, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A70, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_TGL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9A40, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A49, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A59, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A78, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AC0, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AC9, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AD9, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AF8, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_TGL_IDS(MACRO__, ...) \
|
||||
INTEL_TGL_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_TGL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* RKL */
|
||||
#define INTEL_RKL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4C80, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8A, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8B, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8C, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C90, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C9A, ## __VA_ARGS__)
|
||||
|
||||
/* DG1 */
|
||||
#define INTEL_DG1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4905, ## __VA_ARGS__), \
|
||||
MACRO__(0x4906, ## __VA_ARGS__), \
|
||||
MACRO__(0x4907, ## __VA_ARGS__), \
|
||||
MACRO__(0x4908, ## __VA_ARGS__), \
|
||||
MACRO__(0x4909, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-S */
|
||||
#define INTEL_ADLS_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4680, ## __VA_ARGS__), \
|
||||
MACRO__(0x4682, ## __VA_ARGS__), \
|
||||
MACRO__(0x4688, ## __VA_ARGS__), \
|
||||
MACRO__(0x468A, ## __VA_ARGS__), \
|
||||
MACRO__(0x468B, ## __VA_ARGS__), \
|
||||
MACRO__(0x4690, ## __VA_ARGS__), \
|
||||
MACRO__(0x4692, ## __VA_ARGS__), \
|
||||
MACRO__(0x4693, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-P */
|
||||
#define INTEL_ADLP_IDS(MACRO__, ...) \
|
||||
MACRO__(0x46A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A6, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A8, ## __VA_ARGS__), \
|
||||
MACRO__(0x46AA, ## __VA_ARGS__), \
|
||||
MACRO__(0x462A, ## __VA_ARGS__), \
|
||||
MACRO__(0x4626, ## __VA_ARGS__), \
|
||||
MACRO__(0x4628, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C3, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-N */
|
||||
#define INTEL_ADLN_IDS(MACRO__, ...) \
|
||||
MACRO__(0x46D0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D4, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-S */
|
||||
#define INTEL_RPLS_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA780, ## __VA_ARGS__), \
|
||||
MACRO__(0xA781, ## __VA_ARGS__), \
|
||||
MACRO__(0xA782, ## __VA_ARGS__), \
|
||||
MACRO__(0xA783, ## __VA_ARGS__), \
|
||||
MACRO__(0xA788, ## __VA_ARGS__), \
|
||||
MACRO__(0xA789, ## __VA_ARGS__), \
|
||||
MACRO__(0xA78A, ## __VA_ARGS__), \
|
||||
MACRO__(0xA78B, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-U */
|
||||
#define INTEL_RPLU_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA721, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A1, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A9, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AC, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AD, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-P */
|
||||
#define INTEL_RPLP_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA720, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A0, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A8, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AA, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AB, ## __VA_ARGS__)
|
||||
|
||||
/* DG2 */
|
||||
#define INTEL_DG2_G10_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5690, ## __VA_ARGS__), \
|
||||
MACRO__(0x5691, ## __VA_ARGS__), \
|
||||
MACRO__(0x5692, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A1, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A2, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BE, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BF, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_DG2_G11_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5693, ## __VA_ARGS__), \
|
||||
MACRO__(0x5694, ## __VA_ARGS__), \
|
||||
MACRO__(0x5695, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A5, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A6, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B1, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BA, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BB, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BC, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BD, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_DG2_G12_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5696, ## __VA_ARGS__), \
|
||||
MACRO__(0x5697, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A3, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A4, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B2, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B3, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_DG2_IDS(MACRO__, ...) \
|
||||
INTEL_DG2_G10_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_DG2_G11_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_DG2_G12_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ATS_M150_IDS(MACRO__, ...) \
|
||||
MACRO__(0x56C0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56C2, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ATS_M75_IDS(MACRO__, ...) \
|
||||
MACRO__(0x56C1, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ATS_M_IDS(MACRO__, ...) \
|
||||
INTEL_ATS_M150_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_ATS_M75_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* MTL */
|
||||
#define INTEL_MTL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D40, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D41, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D45, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D51, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D55, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D60, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D67, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD1, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD5, ## __VA_ARGS__)
|
||||
|
||||
#endif /* _I915_PCIIDS_H */
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2022 Intel Corporation
|
||||
*/
|
||||
#ifndef _I915_PCIIDS_LOCAL_H_
|
||||
#define _I915_PCIIDS_LOCAL_H_
|
||||
|
||||
#include "i915_pciids.h"
|
||||
|
||||
/* MTL perf */
|
||||
#ifndef INTEL_MTL_M_IDS
|
||||
#define INTEL_MTL_M_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D60, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D67, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_MTL_P_GT2_IDS
|
||||
#define INTEL_MTL_P_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D45, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_MTL_P_GT3_IDS
|
||||
#define INTEL_MTL_P_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D55, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD5, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_MTL_P_IDS
|
||||
#define INTEL_MTL_P_IDS(MACRO__, ...) \
|
||||
INTEL_MTL_P_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_MTL_P_GT3_IDS(MACRO__, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_ARL_GT1_IDS
|
||||
#define INTEL_ARL_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D41, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D67, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_ARL_GT2_IDS
|
||||
#define INTEL_ARL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D51, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD1, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_ARL_IDS
|
||||
#define INTEL_ARL_IDS(MACRO__, ...) \
|
||||
INTEL_ARL_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_ARL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* PVC */
|
||||
#ifndef INTEL_PVC_IDS
|
||||
#define INTEL_PVC_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0BD0, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD1, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD2, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD5, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD6, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD7, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD8, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD9, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BDA, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BDB, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif /* _I915_PCIIDS_LOCAL_H */
|
||||
210
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/igt_perf.c
vendored
Normal file
210
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/igt_perf.c
vendored
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <linux/limits.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "igt_perf.h"
|
||||
|
||||
static char *bus_address(int i915, char *path, int pathlen)
|
||||
{
|
||||
struct stat st;
|
||||
int len = -1;
|
||||
int dir;
|
||||
char *s;
|
||||
|
||||
if (fstat(i915, &st) || !S_ISCHR(st.st_mode))
|
||||
return NULL;
|
||||
|
||||
snprintf(path, pathlen, "/sys/dev/char/%d:%d",
|
||||
major(st.st_rdev), minor(st.st_rdev));
|
||||
|
||||
dir = open(path, O_RDONLY);
|
||||
if (dir != -1) {
|
||||
len = readlinkat(dir, "device", path, pathlen - 1);
|
||||
close(dir);
|
||||
}
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
|
||||
path[len] = '\0';
|
||||
|
||||
/* strip off the relative path */
|
||||
s = strrchr(path, '/');
|
||||
if (s)
|
||||
memmove(path, s + 1, len - (s - path) + 1);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const char *i915_perf_device(int i915, char *buf, int buflen)
|
||||
{
|
||||
char *s;
|
||||
|
||||
#define prefix "i915_"
|
||||
#define plen strlen(prefix)
|
||||
|
||||
if (!buf || buflen < plen)
|
||||
return "i915";
|
||||
|
||||
memcpy(buf, prefix, plen);
|
||||
|
||||
if (!bus_address(i915, buf + plen, buflen - plen) ||
|
||||
strcmp(buf + plen, "0000:00:02.0") == 0) /* legacy name for igfx */
|
||||
buf[plen - 1] = '\0';
|
||||
|
||||
/* Convert all colons in the address to '_', thanks perf! */
|
||||
for (s = buf; *s; s++)
|
||||
if (*s == ':')
|
||||
*s = '_';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *xe_perf_device(int xe, char *buf, int buflen)
|
||||
{
|
||||
char *s;
|
||||
char pref[] = "xe_";
|
||||
int len = strlen(pref);
|
||||
|
||||
|
||||
if (!buf || buflen < len)
|
||||
return "xe";
|
||||
|
||||
memcpy(buf, pref, len);
|
||||
|
||||
if (!bus_address(xe, buf + len, buflen - len))
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
/* Convert all colons in the address to '_', thanks perf! */
|
||||
for (s = buf; *s; s++)
|
||||
if (*s == ':')
|
||||
*s = '_';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
uint64_t xe_perf_type_id(int xe)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
return igt_perf_type_id(xe_perf_device(xe, buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
uint64_t i915_perf_type_id(int i915)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
return igt_perf_type_id(i915_perf_device(i915, buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
uint64_t igt_perf_type_id(const char *device)
|
||||
{
|
||||
char buf[64];
|
||||
ssize_t ret;
|
||||
int fd;
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"/sys/bus/event_source/devices/%s/type", device);
|
||||
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
ret = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
if (ret < 1)
|
||||
return 0;
|
||||
|
||||
buf[ret] = '\0';
|
||||
|
||||
return strtoull(buf, NULL, 0);
|
||||
}
|
||||
|
||||
int igt_perf_events_dir(int i915)
|
||||
{
|
||||
char buf[80];
|
||||
char path[PATH_MAX];
|
||||
|
||||
i915_perf_device(i915, buf, sizeof(buf));
|
||||
snprintf(path, sizeof(path), "/sys/bus/event_source/devices/%s/events", buf);
|
||||
return open(path, O_RDONLY);
|
||||
}
|
||||
|
||||
static int
|
||||
_perf_open(uint64_t type, uint64_t config, int group, uint64_t format)
|
||||
{
|
||||
struct perf_event_attr attr = { };
|
||||
int nr_cpus = get_nprocs_conf();
|
||||
int cpu = 0, ret;
|
||||
|
||||
attr.type = type;
|
||||
if (attr.type == 0)
|
||||
return -ENOENT;
|
||||
|
||||
if (group >= 0)
|
||||
format &= ~PERF_FORMAT_GROUP;
|
||||
|
||||
attr.read_format = format;
|
||||
attr.config = config;
|
||||
attr.use_clockid = 1;
|
||||
attr.clockid = CLOCK_MONOTONIC;
|
||||
|
||||
do {
|
||||
ret = perf_event_open(&attr, -1, cpu++, group, 0);
|
||||
} while ((ret < 0 && errno == EINVAL) && (cpu < nr_cpus));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int perf_igfx_open(uint64_t config)
|
||||
{
|
||||
return _perf_open(igt_perf_type_id("i915"), config, -1,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED);
|
||||
}
|
||||
|
||||
int perf_igfx_open_group(uint64_t config, int group)
|
||||
{
|
||||
return _perf_open(igt_perf_type_id("i915"), config, group,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_GROUP);
|
||||
}
|
||||
|
||||
int perf_xe_open(int xe, uint64_t config)
|
||||
{
|
||||
return _perf_open(xe_perf_type_id(xe), config, -1,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED);
|
||||
}
|
||||
|
||||
int perf_i915_open(int i915, uint64_t config)
|
||||
{
|
||||
return _perf_open(i915_perf_type_id(i915), config, -1,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED);
|
||||
}
|
||||
|
||||
int perf_i915_open_group(int i915, uint64_t config, int group)
|
||||
{
|
||||
return _perf_open(i915_perf_type_id(i915), config, group,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_GROUP);
|
||||
}
|
||||
|
||||
int igt_perf_open(uint64_t type, uint64_t config)
|
||||
{
|
||||
return _perf_open(type, config, -1,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED);
|
||||
}
|
||||
|
||||
int igt_perf_open_group(uint64_t type, uint64_t config, int group)
|
||||
{
|
||||
return _perf_open(type, config, group,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_GROUP);
|
||||
}
|
||||
75
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/igt_perf.h
vendored
Normal file
75
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/igt_perf.h
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright © 2017 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef I915_PERF_H
|
||||
#define I915_PERF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/perf_event.h>
|
||||
#endif
|
||||
|
||||
//#include "igt_gt.h"
|
||||
|
||||
static inline int
|
||||
perf_event_open(struct perf_event_attr *attr,
|
||||
pid_t pid,
|
||||
int cpu,
|
||||
int group_fd,
|
||||
unsigned long flags)
|
||||
{
|
||||
#ifndef __NR_perf_event_open
|
||||
#if defined(__i386__)
|
||||
#define __NR_perf_event_open 336
|
||||
#elif defined(__x86_64__)
|
||||
#define __NR_perf_event_open 298
|
||||
#else
|
||||
#define __NR_perf_event_open 0
|
||||
#endif
|
||||
#endif
|
||||
attr->size = sizeof(*attr);
|
||||
return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
|
||||
}
|
||||
|
||||
uint64_t igt_perf_type_id(const char *device);
|
||||
int igt_perf_events_dir(int i915);
|
||||
int igt_perf_open(uint64_t type, uint64_t config);
|
||||
int igt_perf_open_group(uint64_t type, uint64_t config, int group);
|
||||
|
||||
const char *i915_perf_device(int i915, char *buf, int buflen);
|
||||
uint64_t i915_perf_type_id(int i915);
|
||||
|
||||
const char *xe_perf_device(int xe, char *buf, int buflen);
|
||||
uint64_t xe_perf_type_id(int);
|
||||
|
||||
int perf_igfx_open(uint64_t config);
|
||||
int perf_igfx_open_group(uint64_t config, int group);
|
||||
|
||||
int perf_i915_open(int i915, uint64_t config);
|
||||
int perf_i915_open_group(int i915, uint64_t config, int group);
|
||||
|
||||
int perf_xe_open(int xe, uint64_t config);
|
||||
|
||||
#endif /* I915_PERF_H */
|
||||
233
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/intel_chipset.h
vendored
Normal file
233
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/intel_chipset.h
vendored
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright © 2007 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_CHIPSET_H
|
||||
#define _INTEL_CHIPSET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define BIT(x) (1ul <<(x))
|
||||
|
||||
struct intel_device_info {
|
||||
unsigned graphics_ver;
|
||||
unsigned graphics_rel;
|
||||
unsigned display_ver;
|
||||
unsigned gt; /* 0 if unknown */
|
||||
bool has_4tile : 1;
|
||||
bool has_flatccs : 1;
|
||||
bool has_oam : 1;
|
||||
bool is_mobile : 1;
|
||||
bool is_whitney : 1;
|
||||
bool is_almador : 1;
|
||||
bool is_brookdale : 1;
|
||||
bool is_montara : 1;
|
||||
bool is_springdale : 1;
|
||||
bool is_grantsdale : 1;
|
||||
bool is_alviso : 1;
|
||||
bool is_lakeport : 1;
|
||||
bool is_calistoga : 1;
|
||||
bool is_bearlake : 1;
|
||||
bool is_pineview : 1;
|
||||
bool is_broadwater : 1;
|
||||
bool is_crestline : 1;
|
||||
bool is_eaglelake : 1;
|
||||
bool is_cantiga : 1;
|
||||
bool is_ironlake : 1;
|
||||
bool is_arrandale : 1;
|
||||
bool is_sandybridge : 1;
|
||||
bool is_ivybridge : 1;
|
||||
bool is_valleyview : 1;
|
||||
bool is_haswell : 1;
|
||||
bool is_broadwell : 1;
|
||||
bool is_cherryview : 1;
|
||||
bool is_skylake : 1;
|
||||
bool is_broxton : 1;
|
||||
bool is_kabylake : 1;
|
||||
bool is_geminilake : 1;
|
||||
bool is_coffeelake : 1;
|
||||
bool is_cometlake : 1;
|
||||
bool is_cannonlake : 1;
|
||||
bool is_icelake : 1;
|
||||
bool is_elkhartlake : 1;
|
||||
bool is_jasperlake : 1;
|
||||
bool is_tigerlake : 1;
|
||||
bool is_rocketlake : 1;
|
||||
bool is_dg1 : 1;
|
||||
bool is_dg2 : 1;
|
||||
bool is_alderlake_s : 1;
|
||||
bool is_raptorlake_s : 1;
|
||||
bool is_alderlake_p : 1;
|
||||
bool is_alderlake_n : 1;
|
||||
bool is_meteorlake : 1;
|
||||
bool is_pontevecchio : 1;
|
||||
bool is_lunarlake : 1;
|
||||
bool is_battlemage : 1;
|
||||
const char *codename;
|
||||
};
|
||||
|
||||
const struct intel_device_info *intel_get_device_info(uint16_t devid) __attribute__((pure));
|
||||
|
||||
extern enum pch_type intel_pch;
|
||||
|
||||
enum pch_type {
|
||||
PCH_NONE,
|
||||
PCH_IBX,
|
||||
PCH_CPT,
|
||||
PCH_LPT,
|
||||
};
|
||||
|
||||
void intel_check_pch(void);
|
||||
|
||||
#define HAS_IBX (intel_pch == PCH_IBX)
|
||||
#define HAS_CPT (intel_pch == PCH_CPT)
|
||||
#define HAS_LPT (intel_pch == PCH_LPT)
|
||||
|
||||
#define IP_VER(ver, rel) ((ver) << 8 | (rel))
|
||||
|
||||
/* Exclude chipset #defines, they just add noise */
|
||||
#ifndef __GTK_DOC_IGNORE__
|
||||
|
||||
#define PCI_CHIP_I810 0x7121
|
||||
#define PCI_CHIP_I810_DC100 0x7123
|
||||
#define PCI_CHIP_I810_E 0x7125
|
||||
#define PCI_CHIP_I815 0x1132
|
||||
|
||||
#define PCI_CHIP_I830_M 0x3577
|
||||
#define PCI_CHIP_845_G 0x2562
|
||||
#define PCI_CHIP_I854_G 0x358e
|
||||
#define PCI_CHIP_I855_GM 0x3582
|
||||
#define PCI_CHIP_I865_G 0x2572
|
||||
|
||||
#define PCI_CHIP_I915_G 0x2582
|
||||
#define PCI_CHIP_E7221_G 0x258A
|
||||
#define PCI_CHIP_I915_GM 0x2592
|
||||
#define PCI_CHIP_I945_G 0x2772
|
||||
#define PCI_CHIP_I945_GM 0x27A2
|
||||
#define PCI_CHIP_I945_GME 0x27AE
|
||||
|
||||
#define PCI_CHIP_I965_G 0x29A2
|
||||
#define PCI_CHIP_I965_Q 0x2992
|
||||
#define PCI_CHIP_I965_G_1 0x2982
|
||||
#define PCI_CHIP_I946_GZ 0x2972
|
||||
#define PCI_CHIP_I965_GM 0x2A02
|
||||
#define PCI_CHIP_I965_GME 0x2A12
|
||||
|
||||
#define PCI_CHIP_GM45_GM 0x2A42
|
||||
|
||||
#define PCI_CHIP_Q45_G 0x2E12
|
||||
#define PCI_CHIP_G45_G 0x2E22
|
||||
#define PCI_CHIP_G41_G 0x2E32
|
||||
|
||||
#endif /* __GTK_DOC_IGNORE__ */
|
||||
|
||||
#define IS_915G(devid) (intel_get_device_info(devid)->is_grantsdale)
|
||||
#define IS_915GM(devid) (intel_get_device_info(devid)->is_alviso)
|
||||
|
||||
#define IS_915(devid) (IS_915G(devid) || IS_915GM(devid))
|
||||
|
||||
#define IS_945G(devid) (intel_get_device_info(devid)->is_lakeport)
|
||||
#define IS_945GM(devid) (intel_get_device_info(devid)->is_calistoga)
|
||||
|
||||
#define IS_945(devid) (IS_945G(devid) || \
|
||||
IS_945GM(devid) || \
|
||||
IS_G33(devid))
|
||||
|
||||
#define IS_PINEVIEW(devid) (intel_get_device_info(devid)->is_pineview)
|
||||
#define IS_G33(devid) (intel_get_device_info(devid)->is_bearlake || \
|
||||
intel_get_device_info(devid)->is_pineview)
|
||||
|
||||
#define IS_BROADWATER(devid) (intel_get_device_info(devid)->is_broadwater)
|
||||
#define IS_CRESTLINE(devid) (intel_get_device_info(devid)->is_crestline)
|
||||
|
||||
#define IS_GM45(devid) (intel_get_device_info(devid)->is_cantiga)
|
||||
#define IS_G45(devid) (intel_get_device_info(devid)->is_eaglelake)
|
||||
#define IS_G4X(devid) (IS_G45(devid) || IS_GM45(devid))
|
||||
|
||||
#define IS_IRONLAKE(devid) (intel_get_device_info(devid)->is_ironlake)
|
||||
#define IS_ARRANDALE(devid) (intel_get_device_info(devid)->is_arrandale)
|
||||
#define IS_SANDYBRIDGE(devid) (intel_get_device_info(devid)->is_sandybridge)
|
||||
#define IS_IVYBRIDGE(devid) (intel_get_device_info(devid)->is_ivybridge)
|
||||
#define IS_VALLEYVIEW(devid) (intel_get_device_info(devid)->is_valleyview)
|
||||
#define IS_HASWELL(devid) (intel_get_device_info(devid)->is_haswell)
|
||||
#define IS_BROADWELL(devid) (intel_get_device_info(devid)->is_broadwell)
|
||||
#define IS_CHERRYVIEW(devid) (intel_get_device_info(devid)->is_cherryview)
|
||||
#define IS_SKYLAKE(devid) (intel_get_device_info(devid)->is_skylake)
|
||||
#define IS_BROXTON(devid) (intel_get_device_info(devid)->is_broxton)
|
||||
#define IS_KABYLAKE(devid) (intel_get_device_info(devid)->is_kabylake)
|
||||
#define IS_GEMINILAKE(devid) (intel_get_device_info(devid)->is_geminilake)
|
||||
#define IS_COFFEELAKE(devid) (intel_get_device_info(devid)->is_coffeelake)
|
||||
#define IS_COMETLAKE(devid) (intel_get_device_info(devid)->is_cometlake)
|
||||
#define IS_CANNONLAKE(devid) (intel_get_device_info(devid)->is_cannonlake)
|
||||
#define IS_ICELAKE(devid) (intel_get_device_info(devid)->is_icelake)
|
||||
#define IS_TIGERLAKE(devid) (intel_get_device_info(devid)->is_tigerlake)
|
||||
#define IS_ROCKETLAKE(devid) (intel_get_device_info(devid)->is_rocketlake)
|
||||
#define IS_DG1(devid) (intel_get_device_info(devid)->is_dg1)
|
||||
#define IS_DG2(devid) (intel_get_device_info(devid)->is_dg2)
|
||||
#define IS_ALDERLAKE_S(devid) (intel_get_device_info(devid)->is_alderlake_s)
|
||||
#define IS_RAPTORLAKE_S(devid) (intel_get_device_info(devid)->is_raptorlake_s)
|
||||
#define IS_ALDERLAKE_P(devid) (intel_get_device_info(devid)->is_alderlake_p)
|
||||
#define IS_ALDERLAKE_N(devid) (intel_get_device_info(devid)->is_alderlake_n)
|
||||
#define IS_METEORLAKE(devid) (intel_get_device_info(devid)->is_meteorlake)
|
||||
#define IS_PONTEVECCHIO(devid) (intel_get_device_info(devid)->is_pontevecchio)
|
||||
#define IS_LUNARLAKE(devid) (intel_get_device_info(devid)->is_lunarlake)
|
||||
#define IS_BATTLEMAGE(devid) (intel_get_device_info(devid)->is_battlemage)
|
||||
|
||||
#define IS_GEN(devid, x) (intel_get_device_info(devid)->graphics_ver == x)
|
||||
#define AT_LEAST_GEN(devid, x) (intel_get_device_info(devid)->graphics_ver >= x)
|
||||
#define AT_LEAST_DISPLAY(devid, x) (intel_get_device_info(devid)->display_ver >= x)
|
||||
|
||||
#define IS_GEN2(devid) IS_GEN(devid, 2)
|
||||
#define IS_GEN3(devid) IS_GEN(devid, 3)
|
||||
#define IS_GEN4(devid) IS_GEN(devid, 4)
|
||||
#define IS_GEN5(devid) IS_GEN(devid, 5)
|
||||
#define IS_GEN6(devid) IS_GEN(devid, 6)
|
||||
#define IS_GEN7(devid) IS_GEN(devid, 7)
|
||||
#define IS_GEN8(devid) IS_GEN(devid, 8)
|
||||
#define IS_GEN9(devid) IS_GEN(devid, 9)
|
||||
#define IS_GEN10(devid) IS_GEN(devid, 10)
|
||||
#define IS_GEN11(devid) IS_GEN(devid, 11)
|
||||
#define IS_GEN12(devid) IS_GEN(devid, 12)
|
||||
|
||||
#define IS_MOBILE(devid) (intel_get_device_info(devid)->is_mobile)
|
||||
#define IS_965(devid) AT_LEAST_GEN(devid, 4)
|
||||
|
||||
#define HAS_BSD_RING(devid) AT_LEAST_GEN(devid, 5)
|
||||
#define HAS_BLT_RING(devid) AT_LEAST_GEN(devid, 6)
|
||||
|
||||
#define HAS_PCH_SPLIT(devid) (AT_LEAST_GEN(devid, 5) && \
|
||||
!(IS_VALLEYVIEW(devid) || \
|
||||
IS_CHERRYVIEW(devid) || \
|
||||
IS_BROXTON(devid)))
|
||||
|
||||
#define HAS_4TILE(devid) (intel_get_device_info(devid)->has_4tile)
|
||||
|
||||
#define HAS_FLATCCS(devid) (intel_get_device_info(devid)->has_flatccs)
|
||||
|
||||
#define HAS_OAM(devid) (intel_get_device_info(devid)->has_oam)
|
||||
|
||||
#endif /* _INTEL_CHIPSET_H */
|
||||
653
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/intel_device_info.c
vendored
Normal file
653
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/intel_device_info.c
vendored
Normal file
|
|
@ -0,0 +1,653 @@
|
|||
#include "intel_chipset.h"
|
||||
#include "i915_pciids.h"
|
||||
#include "i915_pciids_local.h"
|
||||
#include "xe_pciids.h"
|
||||
|
||||
#include <strings.h> /* ffs() */
|
||||
|
||||
// from pciaccess.h
|
||||
#define PCI_MATCH_ANY (~0U)
|
||||
|
||||
// from pciaccess.h
|
||||
struct pci_id_match {
|
||||
/**
|
||||
* \name Device / vendor matching controls
|
||||
*
|
||||
* Control the search based on the device, vendor, subdevice, or subvendor
|
||||
* IDs. Setting any of these fields to \c PCI_MATCH_ANY will cause the
|
||||
* field to not be used in the comparison.
|
||||
*/
|
||||
/*@{*/
|
||||
uint32_t vendor_id;
|
||||
uint32_t device_id;
|
||||
uint32_t subvendor_id;
|
||||
uint32_t subdevice_id;
|
||||
/*@}*/
|
||||
|
||||
|
||||
/**
|
||||
* \name Device class matching controls
|
||||
*
|
||||
*/
|
||||
/*@{*/
|
||||
uint32_t device_class;
|
||||
uint32_t device_class_mask;
|
||||
/*@}*/
|
||||
|
||||
intptr_t match_data;
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_generic_info = {
|
||||
.graphics_ver = 0,
|
||||
.display_ver = 0,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i810_info = {
|
||||
.graphics_ver = 1,
|
||||
.display_ver = 1,
|
||||
.is_whitney = true,
|
||||
.codename = "solano" /* 815 == "whitney" ? or vice versa? */
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i815_info = {
|
||||
.graphics_ver = 1,
|
||||
.display_ver = 1,
|
||||
.is_whitney = true,
|
||||
.codename = "whitney"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i830_info = {
|
||||
.graphics_ver = 2,
|
||||
.display_ver = 2,
|
||||
.is_almador = true,
|
||||
.codename = "almador"
|
||||
};
|
||||
static const struct intel_device_info intel_i845_info = {
|
||||
.graphics_ver = 2,
|
||||
.display_ver = 2,
|
||||
.is_brookdale = true,
|
||||
.codename = "brookdale"
|
||||
};
|
||||
static const struct intel_device_info intel_i855_info = {
|
||||
.graphics_ver = 2,
|
||||
.display_ver = 2,
|
||||
.is_mobile = true,
|
||||
.is_montara = true,
|
||||
.codename = "montara"
|
||||
};
|
||||
static const struct intel_device_info intel_i865_info = {
|
||||
.graphics_ver = 2,
|
||||
.display_ver = 2,
|
||||
.is_springdale = true,
|
||||
.codename = "spingdale"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i915_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_grantsdale = true,
|
||||
.codename = "grantsdale"
|
||||
};
|
||||
static const struct intel_device_info intel_i915m_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_mobile = true,
|
||||
.is_alviso = true,
|
||||
.codename = "alviso"
|
||||
};
|
||||
static const struct intel_device_info intel_i945_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_lakeport = true,
|
||||
.codename = "lakeport"
|
||||
};
|
||||
static const struct intel_device_info intel_i945m_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_mobile = true,
|
||||
.is_calistoga = true,
|
||||
.codename = "calistoga"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_g33_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_bearlake = true,
|
||||
.codename = "bearlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_pineview_g_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_pineview = true,
|
||||
.codename = "pineview"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_pineview_m_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_mobile = true,
|
||||
.is_pineview = true,
|
||||
.codename = "pineview"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i965_info = {
|
||||
.graphics_ver = 4,
|
||||
.display_ver = 4,
|
||||
.is_broadwater = true,
|
||||
.codename = "broadwater"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i965m_info = {
|
||||
.graphics_ver = 4,
|
||||
.display_ver = 4,
|
||||
.is_mobile = true,
|
||||
.is_crestline = true,
|
||||
.codename = "crestline"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_g45_info = {
|
||||
.graphics_ver = 4,
|
||||
.display_ver = 4,
|
||||
.is_eaglelake = true,
|
||||
.codename = "eaglelake"
|
||||
};
|
||||
static const struct intel_device_info intel_gm45_info = {
|
||||
.graphics_ver = 4,
|
||||
.display_ver = 4,
|
||||
.is_mobile = true,
|
||||
.is_cantiga = true,
|
||||
.codename = "cantiga"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ironlake_info = {
|
||||
.graphics_ver = 5,
|
||||
.display_ver = 5,
|
||||
.is_ironlake = true,
|
||||
.codename = "ironlake" /* clarkdale? */
|
||||
};
|
||||
static const struct intel_device_info intel_ironlake_m_info = {
|
||||
.graphics_ver = 5,
|
||||
.display_ver = 5,
|
||||
.is_mobile = true,
|
||||
.is_arrandale = true,
|
||||
.codename = "arrandale"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_sandybridge_info = {
|
||||
.graphics_ver = 6,
|
||||
.display_ver = 6,
|
||||
.is_sandybridge = true,
|
||||
.codename = "sandybridge"
|
||||
};
|
||||
static const struct intel_device_info intel_sandybridge_m_info = {
|
||||
.graphics_ver = 6,
|
||||
.display_ver = 6,
|
||||
.is_mobile = true,
|
||||
.is_sandybridge = true,
|
||||
.codename = "sandybridge"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_info = {
|
||||
.graphics_ver = 7,
|
||||
.display_ver = 7,
|
||||
.is_ivybridge = true,
|
||||
.codename = "ivybridge"
|
||||
};
|
||||
static const struct intel_device_info intel_ivybridge_m_info = {
|
||||
.graphics_ver = 7,
|
||||
.display_ver = 7,
|
||||
.is_mobile = true,
|
||||
.is_ivybridge = true,
|
||||
.codename = "ivybridge"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_valleyview_info = {
|
||||
.graphics_ver = 7,
|
||||
.display_ver = 7,
|
||||
.is_valleyview = true,
|
||||
.codename = "valleyview"
|
||||
};
|
||||
|
||||
#define HASWELL_FIELDS \
|
||||
.graphics_ver = 7, \
|
||||
.display_ver = 7, \
|
||||
.is_haswell = true, \
|
||||
.codename = "haswell"
|
||||
|
||||
static const struct intel_device_info intel_haswell_gt1_info = {
|
||||
HASWELL_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_haswell_gt2_info = {
|
||||
HASWELL_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_haswell_gt3_info = {
|
||||
HASWELL_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
#define BROADWELL_FIELDS \
|
||||
.graphics_ver = 8, \
|
||||
.display_ver = 8, \
|
||||
.is_broadwell = true, \
|
||||
.codename = "broadwell"
|
||||
|
||||
static const struct intel_device_info intel_broadwell_gt1_info = {
|
||||
BROADWELL_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_gt2_info = {
|
||||
BROADWELL_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_gt3_info = {
|
||||
BROADWELL_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_unknown_info = {
|
||||
BROADWELL_FIELDS,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_cherryview_info = {
|
||||
.graphics_ver = 8,
|
||||
.display_ver = 8,
|
||||
.is_cherryview = true,
|
||||
.codename = "cherryview"
|
||||
};
|
||||
|
||||
#define SKYLAKE_FIELDS \
|
||||
.graphics_ver = 9, \
|
||||
.display_ver = 9, \
|
||||
.codename = "skylake", \
|
||||
.is_skylake = true
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt1_info = {
|
||||
SKYLAKE_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt2_info = {
|
||||
SKYLAKE_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt3_info = {
|
||||
SKYLAKE_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt4_info = {
|
||||
SKYLAKE_FIELDS,
|
||||
.gt = 4,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broxton_info = {
|
||||
.graphics_ver = 9,
|
||||
.display_ver = 9,
|
||||
.is_broxton = true,
|
||||
.codename = "broxton"
|
||||
};
|
||||
|
||||
#define KABYLAKE_FIELDS \
|
||||
.graphics_ver = 9, \
|
||||
.display_ver = 9, \
|
||||
.is_kabylake = true, \
|
||||
.codename = "kabylake"
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt1_info = {
|
||||
KABYLAKE_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt2_info = {
|
||||
KABYLAKE_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt3_info = {
|
||||
KABYLAKE_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt4_info = {
|
||||
KABYLAKE_FIELDS,
|
||||
.gt = 4,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_geminilake_info = {
|
||||
.graphics_ver = 9,
|
||||
.display_ver = 9,
|
||||
.is_geminilake = true,
|
||||
.codename = "geminilake"
|
||||
};
|
||||
|
||||
#define COFFEELAKE_FIELDS \
|
||||
.graphics_ver = 9, \
|
||||
.display_ver = 9, \
|
||||
.is_coffeelake = true, \
|
||||
.codename = "coffeelake"
|
||||
|
||||
static const struct intel_device_info intel_coffeelake_gt1_info = {
|
||||
COFFEELAKE_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_coffeelake_gt2_info = {
|
||||
COFFEELAKE_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_coffeelake_gt3_info = {
|
||||
COFFEELAKE_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
#define COMETLAKE_FIELDS \
|
||||
.graphics_ver = 9, \
|
||||
.display_ver = 9, \
|
||||
.is_cometlake = true, \
|
||||
.codename = "cometlake"
|
||||
|
||||
static const struct intel_device_info intel_cometlake_gt1_info = {
|
||||
COMETLAKE_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_cometlake_gt2_info = {
|
||||
COMETLAKE_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_cannonlake_info = {
|
||||
.graphics_ver = 10,
|
||||
.display_ver = 10,
|
||||
.is_cannonlake = true,
|
||||
.codename = "cannonlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_icelake_info = {
|
||||
.graphics_ver = 11,
|
||||
.display_ver = 11,
|
||||
.is_icelake = true,
|
||||
.codename = "icelake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_elkhartlake_info = {
|
||||
.graphics_ver = 11,
|
||||
.display_ver = 11,
|
||||
.is_elkhartlake = true,
|
||||
.codename = "elkhartlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_jasperlake_info = {
|
||||
.graphics_ver = 11,
|
||||
.display_ver = 11,
|
||||
.is_jasperlake = true,
|
||||
.codename = "jasperlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_tigerlake_gt1_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_tigerlake = true,
|
||||
.codename = "tigerlake",
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_tigerlake_gt2_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_tigerlake = true,
|
||||
.codename = "tigerlake",
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_rocketlake_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_rocketlake = true,
|
||||
.codename = "rocketlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_dg1_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 10,
|
||||
.display_ver = 12,
|
||||
.is_dg1 = true,
|
||||
.codename = "dg1"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_dg2_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 55,
|
||||
.display_ver = 13,
|
||||
.has_4tile = true,
|
||||
.is_dg2 = true,
|
||||
.codename = "dg2",
|
||||
.has_flatccs = true,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_alderlake_s_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_alderlake_s = true,
|
||||
.codename = "alderlake_s"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_raptorlake_s_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_raptorlake_s = true,
|
||||
.codename = "raptorlake_s"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_alderlake_p_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 13,
|
||||
.is_alderlake_p = true,
|
||||
.codename = "alderlake_p"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_alderlake_n_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 13,
|
||||
.is_alderlake_n = true,
|
||||
.codename = "alderlake_n"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ats_m_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 55,
|
||||
.display_ver = 0, /* no display support */
|
||||
.is_dg2 = true,
|
||||
.has_4tile = true,
|
||||
.codename = "ats_m",
|
||||
.has_flatccs = true,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_meteorlake_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 70,
|
||||
.display_ver = 14,
|
||||
.has_4tile = true,
|
||||
.has_oam = true,
|
||||
.is_meteorlake = true,
|
||||
.codename = "meteorlake",
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_pontevecchio_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 60,
|
||||
.is_pontevecchio = true,
|
||||
.codename = "pontevecchio",
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_lunarlake_info = {
|
||||
.graphics_ver = 20,
|
||||
.graphics_rel = 4,
|
||||
.display_ver = 20,
|
||||
.has_4tile = true,
|
||||
.has_flatccs = true,
|
||||
.has_oam = true,
|
||||
.is_lunarlake = true,
|
||||
.codename = "lunarlake",
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_battlemage_info = {
|
||||
.graphics_ver = 20,
|
||||
.graphics_rel = 1,
|
||||
.display_ver = 14,
|
||||
.has_4tile = true,
|
||||
.has_flatccs = true,
|
||||
.is_battlemage = true,
|
||||
.codename = "battlemage",
|
||||
};
|
||||
|
||||
static const struct pci_id_match intel_device_match[] = {
|
||||
INTEL_I810_IDS(INTEL_VGA_DEVICE, &intel_i810_info),
|
||||
INTEL_I815_IDS(INTEL_VGA_DEVICE, &intel_i815_info),
|
||||
|
||||
INTEL_I830_IDS(INTEL_VGA_DEVICE, &intel_i830_info),
|
||||
INTEL_I845G_IDS(INTEL_VGA_DEVICE, &intel_i845_info),
|
||||
INTEL_I85X_IDS(INTEL_VGA_DEVICE, &intel_i855_info),
|
||||
INTEL_I865G_IDS(INTEL_VGA_DEVICE, &intel_i865_info),
|
||||
|
||||
INTEL_I915G_IDS(INTEL_VGA_DEVICE, &intel_i915_info),
|
||||
INTEL_I915GM_IDS(INTEL_VGA_DEVICE, &intel_i915m_info),
|
||||
INTEL_I945G_IDS(INTEL_VGA_DEVICE, &intel_i945_info),
|
||||
INTEL_I945GM_IDS(INTEL_VGA_DEVICE, &intel_i945m_info),
|
||||
|
||||
INTEL_G33_IDS(INTEL_VGA_DEVICE, &intel_g33_info),
|
||||
INTEL_PNV_G_IDS(INTEL_VGA_DEVICE, &intel_pineview_g_info),
|
||||
INTEL_PNV_M_IDS(INTEL_VGA_DEVICE, &intel_pineview_m_info),
|
||||
|
||||
INTEL_I965G_IDS(INTEL_VGA_DEVICE, &intel_i965_info),
|
||||
INTEL_I965GM_IDS(INTEL_VGA_DEVICE, &intel_i965m_info),
|
||||
|
||||
INTEL_G45_IDS(INTEL_VGA_DEVICE, &intel_g45_info),
|
||||
INTEL_GM45_IDS(INTEL_VGA_DEVICE, &intel_gm45_info),
|
||||
|
||||
INTEL_ILK_D_IDS(INTEL_VGA_DEVICE, &intel_ironlake_info),
|
||||
INTEL_ILK_M_IDS(INTEL_VGA_DEVICE, &intel_ironlake_m_info),
|
||||
|
||||
INTEL_SNB_D_IDS(INTEL_VGA_DEVICE, &intel_sandybridge_info),
|
||||
INTEL_SNB_M_IDS(INTEL_VGA_DEVICE, &intel_sandybridge_m_info),
|
||||
|
||||
INTEL_IVB_D_IDS(INTEL_VGA_DEVICE, &intel_ivybridge_info),
|
||||
INTEL_IVB_M_IDS(INTEL_VGA_DEVICE, &intel_ivybridge_m_info),
|
||||
|
||||
INTEL_HSW_GT1_IDS(INTEL_VGA_DEVICE, &intel_haswell_gt1_info),
|
||||
INTEL_HSW_GT2_IDS(INTEL_VGA_DEVICE, &intel_haswell_gt2_info),
|
||||
INTEL_HSW_GT3_IDS(INTEL_VGA_DEVICE, &intel_haswell_gt3_info),
|
||||
|
||||
INTEL_VLV_IDS(INTEL_VGA_DEVICE, &intel_valleyview_info),
|
||||
|
||||
INTEL_BDW_GT1_IDS(INTEL_VGA_DEVICE, &intel_broadwell_gt1_info),
|
||||
INTEL_BDW_GT2_IDS(INTEL_VGA_DEVICE, &intel_broadwell_gt2_info),
|
||||
INTEL_BDW_GT3_IDS(INTEL_VGA_DEVICE, &intel_broadwell_gt3_info),
|
||||
INTEL_BDW_RSVD_IDS(INTEL_VGA_DEVICE, &intel_broadwell_unknown_info),
|
||||
|
||||
INTEL_CHV_IDS(INTEL_VGA_DEVICE, &intel_cherryview_info),
|
||||
|
||||
INTEL_SKL_GT1_IDS(INTEL_VGA_DEVICE, &intel_skylake_gt1_info),
|
||||
INTEL_SKL_GT2_IDS(INTEL_VGA_DEVICE, &intel_skylake_gt2_info),
|
||||
INTEL_SKL_GT3_IDS(INTEL_VGA_DEVICE, &intel_skylake_gt3_info),
|
||||
INTEL_SKL_GT4_IDS(INTEL_VGA_DEVICE, &intel_skylake_gt4_info),
|
||||
|
||||
INTEL_BXT_IDS(INTEL_VGA_DEVICE, &intel_broxton_info),
|
||||
|
||||
INTEL_KBL_GT1_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt1_info),
|
||||
INTEL_KBL_GT2_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt2_info),
|
||||
INTEL_KBL_GT3_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt3_info),
|
||||
INTEL_KBL_GT4_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt4_info),
|
||||
INTEL_AML_KBL_GT2_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt2_info),
|
||||
|
||||
INTEL_GLK_IDS(INTEL_VGA_DEVICE, &intel_geminilake_info),
|
||||
|
||||
INTEL_CFL_S_GT1_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt1_info),
|
||||
INTEL_CFL_S_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
INTEL_CFL_H_GT1_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt1_info),
|
||||
INTEL_CFL_H_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
INTEL_CFL_U_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
INTEL_CFL_U_GT3_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt3_info),
|
||||
INTEL_WHL_U_GT1_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt1_info),
|
||||
INTEL_WHL_U_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
INTEL_WHL_U_GT3_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt3_info),
|
||||
INTEL_AML_CFL_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
|
||||
INTEL_CML_GT1_IDS(INTEL_VGA_DEVICE, &intel_cometlake_gt1_info),
|
||||
INTEL_CML_GT2_IDS(INTEL_VGA_DEVICE, &intel_cometlake_gt2_info),
|
||||
INTEL_CML_U_GT1_IDS(INTEL_VGA_DEVICE, &intel_cometlake_gt1_info),
|
||||
INTEL_CML_U_GT2_IDS(INTEL_VGA_DEVICE, &intel_cometlake_gt2_info),
|
||||
|
||||
INTEL_CNL_IDS(INTEL_VGA_DEVICE, &intel_cannonlake_info),
|
||||
|
||||
INTEL_ICL_IDS(INTEL_VGA_DEVICE, &intel_icelake_info),
|
||||
|
||||
INTEL_EHL_IDS(INTEL_VGA_DEVICE, &intel_elkhartlake_info),
|
||||
INTEL_JSL_IDS(INTEL_VGA_DEVICE, &intel_jasperlake_info),
|
||||
|
||||
INTEL_TGL_GT1_IDS(INTEL_VGA_DEVICE, &intel_tigerlake_gt1_info),
|
||||
INTEL_TGL_GT2_IDS(INTEL_VGA_DEVICE, &intel_tigerlake_gt2_info),
|
||||
INTEL_RKL_IDS(INTEL_VGA_DEVICE, &intel_rocketlake_info),
|
||||
|
||||
INTEL_DG1_IDS(INTEL_VGA_DEVICE, &intel_dg1_info),
|
||||
INTEL_DG2_IDS(INTEL_VGA_DEVICE, &intel_dg2_info),
|
||||
|
||||
INTEL_ADLS_IDS(INTEL_VGA_DEVICE, &intel_alderlake_s_info),
|
||||
INTEL_RPLS_IDS(INTEL_VGA_DEVICE, &intel_raptorlake_s_info),
|
||||
INTEL_ADLP_IDS(INTEL_VGA_DEVICE, &intel_alderlake_p_info),
|
||||
INTEL_RPLU_IDS(INTEL_VGA_DEVICE, &intel_alderlake_p_info),
|
||||
INTEL_RPLP_IDS(INTEL_VGA_DEVICE, &intel_alderlake_p_info),
|
||||
INTEL_ADLN_IDS(INTEL_VGA_DEVICE, &intel_alderlake_n_info),
|
||||
|
||||
INTEL_ATS_M_IDS(INTEL_VGA_DEVICE, &intel_ats_m_info),
|
||||
|
||||
INTEL_MTL_IDS(INTEL_VGA_DEVICE, &intel_meteorlake_info),
|
||||
|
||||
INTEL_PVC_IDS(INTEL_VGA_DEVICE, &intel_pontevecchio_info),
|
||||
|
||||
XE_LNL_IDS(INTEL_VGA_DEVICE, &intel_lunarlake_info),
|
||||
|
||||
XE_BMG_IDS(INTEL_VGA_DEVICE, &intel_battlemage_info),
|
||||
|
||||
INTEL_VGA_DEVICE(PCI_MATCH_ANY, &intel_generic_info),
|
||||
};
|
||||
|
||||
/**
|
||||
* intel_get_device_info:
|
||||
* @devid: pci device id
|
||||
*
|
||||
* Looks up the Intel GFX device info for the given device id.
|
||||
*
|
||||
* Returns:
|
||||
* The associated intel_get_device_info
|
||||
*/
|
||||
const struct intel_device_info *intel_get_device_info(uint16_t devid)
|
||||
{
|
||||
static const struct intel_device_info *cache = &intel_generic_info;
|
||||
static uint16_t cached_devid;
|
||||
int i;
|
||||
|
||||
if (cached_devid == devid)
|
||||
goto out;
|
||||
|
||||
/* XXX Presort table and bsearch! */
|
||||
for (i = 0; intel_device_match[i].device_id != PCI_MATCH_ANY; i++) {
|
||||
if (devid == intel_device_match[i].device_id)
|
||||
break;
|
||||
}
|
||||
|
||||
cached_devid = devid;
|
||||
cache = (void *)intel_device_match[i].match_data;
|
||||
|
||||
out:
|
||||
return cache;
|
||||
}
|
||||
697
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/intel_gpu_top.c
vendored
Normal file
697
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/intel_gpu_top.c
vendored
Normal file
|
|
@ -0,0 +1,697 @@
|
|||
/*
|
||||
* Copyright © 2007-2023 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "intel_gpu_top.h"
|
||||
#include "i915_drm.h"
|
||||
#include "igt_perf.h"
|
||||
|
||||
#ifdef __clang__ //? Workaround for missing asprintf when compiling with clang, taken from https://stackoverflow.com/a/4899487
|
||||
int asprintf(char **ret, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
*ret = NULL; /* Ensure value can be passed to free() */
|
||||
|
||||
va_start(ap, format);
|
||||
int count = vsnprintf(NULL, 0, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (count >= 0)
|
||||
{
|
||||
char* buffer = malloc(count + 1);
|
||||
if (buffer == NULL)
|
||||
return -1;
|
||||
|
||||
va_start(ap, format);
|
||||
count = vsnprintf(buffer, count + 1, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
free(buffer);
|
||||
return count;
|
||||
}
|
||||
*ret = buffer;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__((format(scanf,3,4)))
|
||||
static int igt_sysfs_scanf(int dir, const char *attr, const char *fmt, ...)
|
||||
{
|
||||
FILE *file;
|
||||
int fd;
|
||||
int ret = -1;
|
||||
|
||||
fd = openat(dir, attr, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
file = fdopen(fd, "r");
|
||||
if (file) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vfscanf(file, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fclose(file);
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pmu_parse(struct pmu_counter *pmu, const char *path, const char *str)
|
||||
{
|
||||
locale_t locale, oldlocale;
|
||||
bool result = true;
|
||||
char buf[128] = {};
|
||||
int dir;
|
||||
|
||||
dir = open(path, O_RDONLY);
|
||||
if (dir < 0)
|
||||
return -errno;
|
||||
|
||||
/* Replace user environment with plain C to match kernel format */
|
||||
locale = newlocale(LC_ALL, "C", 0);
|
||||
oldlocale = uselocale(locale);
|
||||
|
||||
result &= igt_sysfs_scanf(dir, "type", "%"PRIu64, &pmu->type) == 1;
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "events/%s", str);
|
||||
result &= igt_sysfs_scanf(dir, buf, "event=%"PRIx64, &pmu->config) == 1;
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "events/%s.scale", str);
|
||||
result &= igt_sysfs_scanf(dir, buf, "%lf", &pmu->scale) == 1;
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "events/%s.unit", str);
|
||||
result &= igt_sysfs_scanf(dir, buf, "%127s", buf) == 1;
|
||||
pmu->units = strdup(buf);
|
||||
|
||||
uselocale(oldlocale);
|
||||
freelocale(locale);
|
||||
|
||||
close(dir);
|
||||
|
||||
if (!result)
|
||||
return -EINVAL;
|
||||
|
||||
if (isnan(pmu->scale) || !pmu->scale)
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rapl_parse(struct pmu_counter *pmu, const char *str)
|
||||
{
|
||||
const char *expected_units = "Joules";
|
||||
int err;
|
||||
|
||||
err = pmu_parse(pmu, "/sys/devices/power", str);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!pmu->units || strcmp(pmu->units, expected_units)) {
|
||||
fprintf(stderr,
|
||||
"Unexpected units for RAPL %s: found '%s', expected '%s'\n",
|
||||
str, pmu->units, expected_units);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rapl_open(struct pmu_counter *pmu,
|
||||
const char *domain,
|
||||
struct engines *engines)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (rapl_parse(pmu, domain) < 0)
|
||||
return;
|
||||
|
||||
fd = igt_perf_open_group(pmu->type, pmu->config, engines->rapl_fd);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
if (engines->rapl_fd == -1)
|
||||
engines->rapl_fd = fd;
|
||||
|
||||
pmu->idx = engines->num_rapl++;
|
||||
pmu->present = true;
|
||||
}
|
||||
|
||||
static void gpu_power_open(struct pmu_counter *pmu,
|
||||
struct engines *engines)
|
||||
{
|
||||
rapl_open(pmu, "energy-gpu", engines);
|
||||
}
|
||||
|
||||
static void pkg_power_open(struct pmu_counter *pmu,
|
||||
struct engines *engines)
|
||||
{
|
||||
rapl_open(pmu, "energy-pkg", engines);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
get_pmu_config(int dirfd, const char *name, const char *counter)
|
||||
{
|
||||
char buf[128], *p;
|
||||
int fd, ret;
|
||||
|
||||
ret = snprintf(buf, sizeof(buf), "%s-%s", name, counter);
|
||||
if (ret < 0 || ret == sizeof(buf))
|
||||
return -1;
|
||||
|
||||
fd = openat(dirfd, buf, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
ret = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (ret <= 0)
|
||||
return -1;
|
||||
|
||||
p = index(buf, '0');
|
||||
if (!p)
|
||||
return -1;
|
||||
|
||||
return strtoul(p, NULL, 0);
|
||||
}
|
||||
|
||||
#define engine_ptr(engines, n) (&engines->engine + (n))
|
||||
|
||||
static const char *class_display_name(unsigned int class)
|
||||
{
|
||||
switch (class) {
|
||||
case I915_ENGINE_CLASS_RENDER:
|
||||
return "Render/3D";
|
||||
case I915_ENGINE_CLASS_COPY:
|
||||
return "Blitter";
|
||||
case I915_ENGINE_CLASS_VIDEO:
|
||||
return "Video";
|
||||
case I915_ENGINE_CLASS_VIDEO_ENHANCE:
|
||||
return "VideoEnhance";
|
||||
case I915_ENGINE_CLASS_COMPUTE:
|
||||
return "Compute";
|
||||
default:
|
||||
return "[unknown]";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *class_short_name(unsigned int class)
|
||||
{
|
||||
switch (class) {
|
||||
case I915_ENGINE_CLASS_RENDER:
|
||||
return "RCS";
|
||||
case I915_ENGINE_CLASS_COPY:
|
||||
return "BCS";
|
||||
case I915_ENGINE_CLASS_VIDEO:
|
||||
return "VCS";
|
||||
case I915_ENGINE_CLASS_VIDEO_ENHANCE:
|
||||
return "VECS";
|
||||
case I915_ENGINE_CLASS_COMPUTE:
|
||||
return "CCS";
|
||||
default:
|
||||
return "UNKN";
|
||||
}
|
||||
}
|
||||
|
||||
static int engine_cmp(const void *__a, const void *__b)
|
||||
{
|
||||
const struct engine *a = (struct engine *)__a;
|
||||
const struct engine *b = (struct engine *)__b;
|
||||
|
||||
if (a->class != b->class)
|
||||
return a->class - b->class;
|
||||
else
|
||||
return a->instance - b->instance;
|
||||
}
|
||||
|
||||
#define is_igpu(x) (strcmp(x, "i915") == 0)
|
||||
|
||||
struct engines *discover_engines(const char *device)
|
||||
{
|
||||
char sysfs_root[PATH_MAX];
|
||||
struct engines *engines;
|
||||
struct dirent *dent;
|
||||
int ret = 0;
|
||||
DIR *d;
|
||||
|
||||
snprintf(sysfs_root, sizeof(sysfs_root),
|
||||
"/sys/devices/%s/events", device);
|
||||
|
||||
engines = malloc(sizeof(struct engines));
|
||||
if (!engines)
|
||||
return NULL;
|
||||
|
||||
memset(engines, 0, sizeof(*engines));
|
||||
|
||||
engines->num_engines = 0;
|
||||
engines->device = device;
|
||||
engines->discrete = !is_igpu(device);
|
||||
|
||||
d = opendir(sysfs_root);
|
||||
if (!d)
|
||||
goto err;
|
||||
|
||||
while ((dent = readdir(d)) != NULL) {
|
||||
const char *endswith = "-busy";
|
||||
const unsigned int endlen = strlen(endswith);
|
||||
struct engine *engine =
|
||||
engine_ptr(engines, engines->num_engines);
|
||||
char buf[256];
|
||||
|
||||
if (dent->d_type != DT_REG)
|
||||
continue;
|
||||
|
||||
if (strlen(dent->d_name) >= sizeof(buf)) {
|
||||
ret = ENAMETOOLONG;
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(buf, dent->d_name);
|
||||
|
||||
/* xxxN-busy */
|
||||
if (strlen(buf) < (endlen + 4))
|
||||
continue;
|
||||
if (strcmp(&buf[strlen(buf) - endlen], endswith))
|
||||
continue;
|
||||
|
||||
memset(engine, 0, sizeof(*engine));
|
||||
|
||||
buf[strlen(buf) - endlen] = 0;
|
||||
engine->name = strdup(buf);
|
||||
if (!engine->name) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
engine->busy.config = get_pmu_config(dirfd(d), engine->name,
|
||||
"busy");
|
||||
if (engine->busy.config == -1) {
|
||||
ret = ENOENT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Double check config is an engine config. */
|
||||
if (engine->busy.config >= __I915_PMU_OTHER(0)) {
|
||||
free((void *)engine->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
engine->class = (engine->busy.config &
|
||||
(__I915_PMU_OTHER(0) - 1)) >>
|
||||
I915_PMU_CLASS_SHIFT;
|
||||
|
||||
engine->instance = (engine->busy.config >>
|
||||
I915_PMU_SAMPLE_BITS) &
|
||||
((1 << I915_PMU_SAMPLE_INSTANCE_BITS) - 1);
|
||||
|
||||
ret = asprintf(&engine->display_name, "%s/%u",
|
||||
class_display_name(engine->class),
|
||||
engine->instance);
|
||||
if (ret <= 0) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = asprintf(&engine->short_name, "%s/%u",
|
||||
class_short_name(engine->class),
|
||||
engine->instance);
|
||||
if (ret <= 0) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
engines->num_engines++;
|
||||
engines = realloc(engines, sizeof(struct engines) +
|
||||
engines->num_engines * sizeof(struct engine));
|
||||
if (!engines) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
errno = ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
qsort(engine_ptr(engines, 0), engines->num_engines,
|
||||
sizeof(struct engine), engine_cmp);
|
||||
|
||||
engines->root = d;
|
||||
|
||||
return engines;
|
||||
|
||||
err:
|
||||
free(engines);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_engines(struct engines *engines)
|
||||
{
|
||||
struct pmu_counter **pmu, *free_list[] = {
|
||||
&engines->r_gpu,
|
||||
&engines->r_pkg,
|
||||
&engines->imc_reads,
|
||||
&engines->imc_writes,
|
||||
NULL
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
if (!engines)
|
||||
return;
|
||||
|
||||
for (pmu = &free_list[0]; *pmu; pmu++) {
|
||||
if ((*pmu)->present)
|
||||
free((char *)(*pmu)->units);
|
||||
}
|
||||
|
||||
for (i = 0; i < engines->num_engines; i++) {
|
||||
struct engine *engine = engine_ptr(engines, i);
|
||||
|
||||
free((char *)engine->name);
|
||||
free((char *)engine->short_name);
|
||||
free((char *)engine->display_name);
|
||||
}
|
||||
|
||||
closedir(engines->root);
|
||||
|
||||
free(engines->class);
|
||||
free(engines);
|
||||
}
|
||||
|
||||
#define _open_pmu(type, cnt, pmu, fd) \
|
||||
({ \
|
||||
int fd__; \
|
||||
\
|
||||
fd__ = igt_perf_open_group((type), (pmu)->config, (fd)); \
|
||||
if (fd__ >= 0) { \
|
||||
if ((fd) == -1) \
|
||||
(fd) = fd__; \
|
||||
(pmu)->present = true; \
|
||||
(pmu)->idx = (cnt)++; \
|
||||
} \
|
||||
\
|
||||
fd__; \
|
||||
})
|
||||
|
||||
static int imc_parse(struct pmu_counter *pmu, const char *str)
|
||||
{
|
||||
return pmu_parse(pmu, "/sys/devices/uncore_imc", str);
|
||||
}
|
||||
|
||||
static void
|
||||
imc_open(struct pmu_counter *pmu,
|
||||
const char *domain,
|
||||
struct engines *engines)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (imc_parse(pmu, domain) < 0)
|
||||
return;
|
||||
|
||||
fd = igt_perf_open_group(pmu->type, pmu->config, engines->imc_fd);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
if (engines->imc_fd == -1)
|
||||
engines->imc_fd = fd;
|
||||
|
||||
pmu->idx = engines->num_imc++;
|
||||
pmu->present = true;
|
||||
}
|
||||
|
||||
static void imc_writes_open(struct pmu_counter *pmu, struct engines *engines)
|
||||
{
|
||||
imc_open(pmu, "data_writes", engines);
|
||||
}
|
||||
|
||||
static void imc_reads_open(struct pmu_counter *pmu, struct engines *engines)
|
||||
{
|
||||
imc_open(pmu, "data_reads", engines);
|
||||
}
|
||||
|
||||
static int get_num_gts(uint64_t type)
|
||||
{
|
||||
int fd, cnt;
|
||||
|
||||
errno = 0;
|
||||
for (cnt = 0; cnt < MAX_GTS; cnt++) {
|
||||
fd = igt_perf_open(type, __I915_PMU_INTERRUPTS(cnt));
|
||||
if (fd < 0)
|
||||
break;
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (!cnt || (errno && errno != ENOENT))
|
||||
cnt = -errno;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static void init_aggregate_counters(struct engines *engines)
|
||||
{
|
||||
struct pmu_counter *pmu;
|
||||
|
||||
pmu = &engines->freq_req;
|
||||
pmu->type = igt_perf_type_id(engines->device);
|
||||
pmu->config = I915_PMU_REQUESTED_FREQUENCY;
|
||||
pmu->present = true;
|
||||
|
||||
pmu = &engines->freq_act;
|
||||
pmu->type = igt_perf_type_id(engines->device);
|
||||
pmu->config = I915_PMU_ACTUAL_FREQUENCY;
|
||||
pmu->present = true;
|
||||
|
||||
pmu = &engines->rc6;
|
||||
pmu->type = igt_perf_type_id(engines->device);
|
||||
pmu->config = I915_PMU_RC6_RESIDENCY;
|
||||
pmu->present = true;
|
||||
}
|
||||
|
||||
int pmu_init(struct engines *engines)
|
||||
{
|
||||
unsigned int i;
|
||||
int fd;
|
||||
uint64_t type = igt_perf_type_id(engines->device);
|
||||
|
||||
engines->fd = -1;
|
||||
engines->num_counters = 0;
|
||||
engines->num_gts = get_num_gts(type);
|
||||
if (engines->num_gts <= 0)
|
||||
return -1;
|
||||
|
||||
engines->irq.config = I915_PMU_INTERRUPTS;
|
||||
fd = _open_pmu(type, engines->num_counters, &engines->irq, engines->fd);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
init_aggregate_counters(engines);
|
||||
|
||||
for (i = 0; i < engines->num_gts; i++) {
|
||||
engines->freq_req_gt[i].config = __I915_PMU_REQUESTED_FREQUENCY(i);
|
||||
_open_pmu(type, engines->num_counters, &engines->freq_req_gt[i], engines->fd);
|
||||
|
||||
engines->freq_act_gt[i].config = __I915_PMU_ACTUAL_FREQUENCY(i);
|
||||
_open_pmu(type, engines->num_counters, &engines->freq_act_gt[i], engines->fd);
|
||||
|
||||
engines->rc6_gt[i].config = __I915_PMU_RC6_RESIDENCY(i);
|
||||
_open_pmu(type, engines->num_counters, &engines->rc6_gt[i], engines->fd);
|
||||
}
|
||||
|
||||
for (i = 0; i < engines->num_engines; i++) {
|
||||
struct engine *engine = engine_ptr(engines, i);
|
||||
struct {
|
||||
struct pmu_counter *pmu;
|
||||
const char *counter;
|
||||
} *cnt, counters[] = {
|
||||
{ .pmu = &engine->busy, .counter = "busy" },
|
||||
{ .pmu = &engine->wait, .counter = "wait" },
|
||||
{ .pmu = &engine->sema, .counter = "sema" },
|
||||
{ .pmu = NULL, .counter = NULL },
|
||||
};
|
||||
|
||||
for (cnt = counters; cnt->pmu; cnt++) {
|
||||
if (!cnt->pmu->config)
|
||||
cnt->pmu->config =
|
||||
get_pmu_config(dirfd(engines->root),
|
||||
engine->name,
|
||||
cnt->counter);
|
||||
fd = _open_pmu(type, engines->num_counters, cnt->pmu,
|
||||
engines->fd);
|
||||
if (fd >= 0)
|
||||
engine->num_counters++;
|
||||
}
|
||||
}
|
||||
|
||||
engines->rapl_fd = -1;
|
||||
if (!engines->discrete) {
|
||||
gpu_power_open(&engines->r_gpu, engines);
|
||||
pkg_power_open(&engines->r_pkg, engines);
|
||||
}
|
||||
|
||||
engines->imc_fd = -1;
|
||||
imc_reads_open(&engines->imc_reads, engines);
|
||||
imc_writes_open(&engines->imc_writes, engines);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t pmu_read_multi(int fd, unsigned int num, uint64_t *val)
|
||||
{
|
||||
uint64_t buf[2 + num];
|
||||
unsigned int i;
|
||||
ssize_t len;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
assert(len == sizeof(buf));
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
val[i] = buf[2 + i];
|
||||
|
||||
return buf[1];
|
||||
}
|
||||
|
||||
double pmu_calc(struct pmu_pair *p, double d, double t, double s)
|
||||
{
|
||||
double v;
|
||||
|
||||
v = p->cur - p->prev;
|
||||
v /= d;
|
||||
v /= t;
|
||||
v *= s;
|
||||
|
||||
if (s == 100.0 && v > 100.0)
|
||||
v = 100.0;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void __update_sample(struct pmu_counter *counter, uint64_t val)
|
||||
{
|
||||
counter->val.prev = counter->val.cur;
|
||||
counter->val.cur = val;
|
||||
}
|
||||
|
||||
static void update_sample(struct pmu_counter *counter, uint64_t *val)
|
||||
{
|
||||
if (counter->present)
|
||||
__update_sample(counter, val[counter->idx]);
|
||||
}
|
||||
|
||||
void pmu_sample(struct engines *engines)
|
||||
{
|
||||
const int num_val = engines->num_counters;
|
||||
uint64_t val[2 + num_val];
|
||||
unsigned int i;
|
||||
|
||||
engines->ts.prev = engines->ts.cur;
|
||||
engines->ts.cur = pmu_read_multi(engines->fd, num_val, val);
|
||||
|
||||
engines->freq_req.val.cur = engines->freq_req.val.prev = 0;
|
||||
engines->freq_act.val.cur = engines->freq_act.val.prev = 0;
|
||||
engines->rc6.val.cur = engines->rc6.val.prev = 0;
|
||||
|
||||
for (i = 0; i < engines->num_gts; i++) {
|
||||
update_sample(&engines->freq_req_gt[i], val);
|
||||
engines->freq_req.val.cur += engines->freq_req_gt[i].val.cur;
|
||||
engines->freq_req.val.prev += engines->freq_req_gt[i].val.prev;
|
||||
|
||||
update_sample(&engines->freq_act_gt[i], val);
|
||||
engines->freq_act.val.cur += engines->freq_act_gt[i].val.cur;
|
||||
engines->freq_act.val.prev += engines->freq_act_gt[i].val.prev;
|
||||
|
||||
update_sample(&engines->rc6_gt[i], val);
|
||||
engines->rc6.val.cur += engines->rc6_gt[i].val.cur;
|
||||
engines->rc6.val.prev += engines->rc6_gt[i].val.prev;
|
||||
}
|
||||
|
||||
engines->freq_req.val.cur /= engines->num_gts;
|
||||
engines->freq_req.val.prev /= engines->num_gts;
|
||||
|
||||
engines->freq_act.val.cur /= engines->num_gts;
|
||||
engines->freq_act.val.prev /= engines->num_gts;
|
||||
|
||||
engines->rc6.val.cur /= engines->num_gts;
|
||||
engines->rc6.val.prev /= engines->num_gts;
|
||||
|
||||
update_sample(&engines->irq, val);
|
||||
|
||||
for (i = 0; i < engines->num_engines; i++) {
|
||||
struct engine *engine = engine_ptr(engines, i);
|
||||
|
||||
update_sample(&engine->busy, val);
|
||||
update_sample(&engine->sema, val);
|
||||
update_sample(&engine->wait, val);
|
||||
}
|
||||
|
||||
if (engines->num_rapl) {
|
||||
pmu_read_multi(engines->rapl_fd, engines->num_rapl, val);
|
||||
update_sample(&engines->r_gpu, val);
|
||||
update_sample(&engines->r_pkg, val);
|
||||
}
|
||||
|
||||
if (engines->num_imc) {
|
||||
pmu_read_multi(engines->imc_fd, engines->num_imc, val);
|
||||
update_sample(&engines->imc_reads, val);
|
||||
update_sample(&engines->imc_writes, val);
|
||||
}
|
||||
}
|
||||
95
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/intel_gpu_top.h
vendored
Normal file
95
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/intel_gpu_top.h
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#ifndef INTEL_GPU_TOP_H
|
||||
#define INTEL_GPU_TOP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <dirent.h>
|
||||
|
||||
struct pmu_pair {
|
||||
uint64_t cur;
|
||||
uint64_t prev;
|
||||
};
|
||||
|
||||
struct pmu_counter {
|
||||
uint64_t type;
|
||||
uint64_t config;
|
||||
unsigned int idx;
|
||||
struct pmu_pair val;
|
||||
double scale;
|
||||
const char *units;
|
||||
bool present;
|
||||
};
|
||||
|
||||
struct engine_class {
|
||||
unsigned int engine_class;
|
||||
const char *name;
|
||||
unsigned int num_engines;
|
||||
};
|
||||
|
||||
struct engine {
|
||||
const char *name;
|
||||
char *display_name;
|
||||
char *short_name;
|
||||
|
||||
unsigned int class;
|
||||
unsigned int instance;
|
||||
|
||||
unsigned int num_counters;
|
||||
|
||||
struct pmu_counter busy;
|
||||
struct pmu_counter wait;
|
||||
struct pmu_counter sema;
|
||||
};
|
||||
|
||||
#define MAX_GTS 4
|
||||
struct engines {
|
||||
unsigned int num_engines;
|
||||
unsigned int num_classes;
|
||||
struct engine_class *class;
|
||||
unsigned int num_counters;
|
||||
DIR *root;
|
||||
int fd;
|
||||
struct pmu_pair ts;
|
||||
|
||||
int rapl_fd;
|
||||
struct pmu_counter r_gpu, r_pkg;
|
||||
unsigned int num_rapl;
|
||||
|
||||
int imc_fd;
|
||||
struct pmu_counter imc_reads;
|
||||
struct pmu_counter imc_writes;
|
||||
unsigned int num_imc;
|
||||
|
||||
struct pmu_counter freq_req;
|
||||
struct pmu_counter freq_req_gt[MAX_GTS];
|
||||
struct pmu_counter freq_act;
|
||||
struct pmu_counter freq_act_gt[MAX_GTS];
|
||||
struct pmu_counter irq;
|
||||
struct pmu_counter rc6;
|
||||
struct pmu_counter rc6_gt[MAX_GTS];
|
||||
|
||||
bool discrete;
|
||||
char *device;
|
||||
|
||||
int num_gts;
|
||||
|
||||
/* Do not edit below this line.
|
||||
* This structure is reallocated every time a new engine is
|
||||
* found and size is increased by sizeof (engine).
|
||||
*/
|
||||
|
||||
struct engine engine;
|
||||
|
||||
};
|
||||
|
||||
struct engines *discover_engines(const char *device);
|
||||
void free_engines(struct engines *engines);
|
||||
int pmu_init(struct engines *engines);
|
||||
void pmu_sample(struct engines *engines);
|
||||
double pmu_calc(struct pmu_pair *p, double d, double t, double s);
|
||||
|
||||
char* find_intel_gpu_dir();
|
||||
char* get_intel_device_id(const char* vendor_path);
|
||||
char *get_intel_device_name(const char *device_id);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "intel_gpu_top.h"
|
||||
#include "intel_chipset.h"
|
||||
|
||||
#define VENDOR_ID "0x8086"
|
||||
#define SYSFS_PATH "/sys/class/drm"
|
||||
#define VENDOR_FILE "vendor"
|
||||
#define DEVICE_FILE "device"
|
||||
|
||||
char* find_intel_gpu_dir() {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
static char path[256];
|
||||
char vendor_path[256];
|
||||
char vendor_id[16];
|
||||
|
||||
if ((dir = opendir(SYSFS_PATH)) == NULL) {
|
||||
perror("opendir");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
// Construct the path to the vendor file
|
||||
snprintf(vendor_path, sizeof(vendor_path), "%s/%s/device/%s", SYSFS_PATH, entry->d_name, VENDOR_FILE);
|
||||
|
||||
// Check if the vendor file exists
|
||||
if (access(vendor_path, F_OK) != -1) {
|
||||
FILE *file = fopen(vendor_path, "r");
|
||||
if (file) {
|
||||
if (fgets(vendor_id, sizeof(vendor_id), file)) {
|
||||
// Trim the newline character
|
||||
vendor_id[strcspn(vendor_id, "\n")] = 0;
|
||||
|
||||
if (strcmp(vendor_id, VENDOR_ID) == 0) {
|
||||
// Return the parent directory (i.e., /sys/class/drm/card*)
|
||||
snprintf(path, sizeof(path), "%s/%s", SYSFS_PATH, entry->d_name);
|
||||
fclose(file);
|
||||
closedir(dir);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return NULL; // Intel GPU not found
|
||||
}
|
||||
|
||||
char* get_intel_device_id(const char* gpu_dir) {
|
||||
static char device_path[256];
|
||||
char device_id[16];
|
||||
|
||||
// Construct the path to the device file
|
||||
snprintf(device_path, sizeof(device_path), "%s/device/%s", gpu_dir, DEVICE_FILE);
|
||||
|
||||
FILE *file = fopen(device_path, "r");
|
||||
if (file) {
|
||||
if (fgets(device_id, sizeof(device_id), file)) {
|
||||
fclose(file);
|
||||
// Trim the newline character
|
||||
device_id[strcspn(device_id, "\n")] = 0;
|
||||
// Return a copy of the device ID
|
||||
return strdup(device_id);
|
||||
}
|
||||
fclose(file);
|
||||
} else {
|
||||
perror("fopen");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_intel_device_name(const char *device_id) {
|
||||
uint16_t devid = strtol(device_id, NULL, 16);
|
||||
char dev_name[256];
|
||||
char full_name[256];
|
||||
const struct intel_device_info *info = intel_get_device_info(devid);
|
||||
if (info) {
|
||||
if (info->codename == NULL) {
|
||||
strcpy(dev_name, "(unknown)");
|
||||
} else {
|
||||
strcpy(dev_name, info->codename);
|
||||
dev_name[0] = toupper(dev_name[0]);
|
||||
}
|
||||
snprintf(full_name, sizeof(full_name), "Intel %s (Gen%u)", dev_name, info->graphics_ver);
|
||||
return strdup(full_name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
2
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/source.txt
vendored
Normal file
2
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/source.txt
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
0f02dc176959e6296866b1bafd3982e277a5e44b
|
||||
https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
|
||||
218
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/xe_pciids.h
vendored
Normal file
218
libs/external/chat-vault/monitoring/grafana/monitor-tui/src/linux/intel_gpu_top/xe_pciids.h
vendored
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2022 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef _XE_PCIIDS_H_
|
||||
#define _XE_PCIIDS_H_
|
||||
|
||||
/*
|
||||
* Lists below can be turned into initializers for a struct pci_device_id
|
||||
* by defining INTEL_VGA_DEVICE:
|
||||
*
|
||||
* #define INTEL_VGA_DEVICE(id, info) { \
|
||||
* 0x8086, id, \
|
||||
* ~0, ~0, \
|
||||
* 0x030000, 0xff0000, \
|
||||
* (unsigned long) info }
|
||||
*
|
||||
* And then calling like:
|
||||
*
|
||||
* XE_TGL_12_GT1_IDS(INTEL_VGA_DEVICE, ## __VA_ARGS__)
|
||||
*
|
||||
* To turn them into something else, just provide a different macro passed as
|
||||
* first argument.
|
||||
*/
|
||||
|
||||
/* TGL */
|
||||
#define XE_TGL_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9A60, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A68, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A70, ## __VA_ARGS__)
|
||||
|
||||
#define XE_TGL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9A40, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A49, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A59, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A78, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AC0, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AC9, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AD9, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AF8, ## __VA_ARGS__)
|
||||
|
||||
#define XE_TGL_IDS(MACRO__, ...) \
|
||||
XE_TGL_GT1_IDS(MACRO__, ## __VA_ARGS__),\
|
||||
XE_TGL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* RKL */
|
||||
#define XE_RKL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4C80, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8A, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8B, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8C, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C90, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C9A, ## __VA_ARGS__)
|
||||
|
||||
/* DG1 */
|
||||
#define XE_DG1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4905, ## __VA_ARGS__), \
|
||||
MACRO__(0x4906, ## __VA_ARGS__), \
|
||||
MACRO__(0x4907, ## __VA_ARGS__), \
|
||||
MACRO__(0x4908, ## __VA_ARGS__), \
|
||||
MACRO__(0x4909, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-S */
|
||||
#define XE_ADLS_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4680, ## __VA_ARGS__), \
|
||||
MACRO__(0x4682, ## __VA_ARGS__), \
|
||||
MACRO__(0x4688, ## __VA_ARGS__), \
|
||||
MACRO__(0x468A, ## __VA_ARGS__), \
|
||||
MACRO__(0x468B, ## __VA_ARGS__), \
|
||||
MACRO__(0x4690, ## __VA_ARGS__), \
|
||||
MACRO__(0x4692, ## __VA_ARGS__), \
|
||||
MACRO__(0x4693, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-P */
|
||||
#define XE_ADLP_IDS(MACRO__, ...) \
|
||||
MACRO__(0x46A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A6, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A8, ## __VA_ARGS__), \
|
||||
MACRO__(0x46AA, ## __VA_ARGS__), \
|
||||
MACRO__(0x462A, ## __VA_ARGS__), \
|
||||
MACRO__(0x4626, ## __VA_ARGS__), \
|
||||
MACRO__(0x4628, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C3, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-N */
|
||||
#define XE_ADLN_IDS(MACRO__, ...) \
|
||||
MACRO__(0x46D0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D2, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-S */
|
||||
#define XE_RPLS_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA780, ## __VA_ARGS__), \
|
||||
MACRO__(0xA781, ## __VA_ARGS__), \
|
||||
MACRO__(0xA782, ## __VA_ARGS__), \
|
||||
MACRO__(0xA783, ## __VA_ARGS__), \
|
||||
MACRO__(0xA788, ## __VA_ARGS__), \
|
||||
MACRO__(0xA789, ## __VA_ARGS__), \
|
||||
MACRO__(0xA78A, ## __VA_ARGS__), \
|
||||
MACRO__(0xA78B, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-U */
|
||||
#define XE_RPLU_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA721, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A1, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A9, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AC, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AD, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-P */
|
||||
#define XE_RPLP_IDS(MACRO__, ...) \
|
||||
XE_RPLU_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0xA720, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A0, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A8, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AA, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AB, ## __VA_ARGS__)
|
||||
|
||||
/* DG2 */
|
||||
#define XE_DG2_G10_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5690, ## __VA_ARGS__), \
|
||||
MACRO__(0x5691, ## __VA_ARGS__), \
|
||||
MACRO__(0x5692, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A1, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A2, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BE, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BF, ## __VA_ARGS__)
|
||||
|
||||
#define XE_DG2_G11_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5693, ## __VA_ARGS__), \
|
||||
MACRO__(0x5694, ## __VA_ARGS__), \
|
||||
MACRO__(0x5695, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A5, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A6, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B1, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BA, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BB, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BC, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BD, ## __VA_ARGS__)
|
||||
|
||||
#define XE_DG2_G12_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5696, ## __VA_ARGS__), \
|
||||
MACRO__(0x5697, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A3, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A4, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B2, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B3, ## __VA_ARGS__)
|
||||
|
||||
#define XE_DG2_IDS(MACRO__, ...) \
|
||||
XE_DG2_G10_IDS(MACRO__, ## __VA_ARGS__),\
|
||||
XE_DG2_G11_IDS(MACRO__, ## __VA_ARGS__),\
|
||||
XE_DG2_G12_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define XE_ATS_M150_IDS(MACRO__, ...) \
|
||||
MACRO__(0x56C0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56C2, ## __VA_ARGS__)
|
||||
|
||||
#define XE_ATS_M75_IDS(MACRO__, ...) \
|
||||
MACRO__(0x56C1, ## __VA_ARGS__)
|
||||
|
||||
#define XE_ATS_M_IDS(MACRO__, ...) \
|
||||
XE_ATS_M150_IDS(MACRO__, ## __VA_ARGS__),\
|
||||
XE_ATS_M75_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* MTL / ARL */
|
||||
#define XE_MTL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D40, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D41, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D45, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D51, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D55, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D60, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D67, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD1, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD5, ## __VA_ARGS__)
|
||||
|
||||
/* PVC */
|
||||
#define XE_PVC_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0B69, ## __VA_ARGS__), \
|
||||
MACRO__(0x0B6E, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD4, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD5, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD6, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD7, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD8, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD9, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BDA, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BDB, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BE0, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BE1, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BE5, ## __VA_ARGS__)
|
||||
|
||||
#define XE_LNL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x6420, ## __VA_ARGS__), \
|
||||
MACRO__(0x64A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x64B0, ## __VA_ARGS__)
|
||||
|
||||
#define XE_BMG_IDS(MACRO__, ...) \
|
||||
MACRO__(0xE202, ## __VA_ARGS__), \
|
||||
MACRO__(0xE20B, ## __VA_ARGS__), \
|
||||
MACRO__(0xE20C, ## __VA_ARGS__), \
|
||||
MACRO__(0xE20D, ## __VA_ARGS__), \
|
||||
MACRO__(0xE212, ## __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "btop.hpp"
|
||||
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
auto main(int argc, const char* argv[]) -> int {
|
||||
return btop_main(std::views::counted(std::next(argv), argc - 1) | std::ranges::to<std::vector<std::string_view>>());
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue